Pull to refresh

Comments 58

Аж 18 плюсов и ни одного минуса? Прям пахнет "объективностью".

Под такое описание подходит С++, взятый 9 раз. И даже "объективностью" тоже попахивает (от слова "объект").

Держите один: тернарного оператора (это который ?:) в Котлине нет. Вместо `a = (b == c) ? d: e` нужно писать `a = if (b == c) d else e` (точки с запятыми и фигурные скобки расставить по вкусу).

Совсем некритичный недостаток - тут просто все современные языки делятся на два класса:

  1. Инструкции = выражения - корни растут из функциональной парадигмы

  2. Инструкции ≠ выражения - корни растут из императивной парадигмы

Ну и бывают гибриды, переходящие от группы 2. к группе 1.

Тернарный оператор обычно реализован во второй группе языков и редко в первой.

Kotlin в большей степени относится ко первой группе ЯП

И отсутствие тернарного оператора не так уж удлиняет код и не лишает его читаемости - зато ключевое слово when очень хорошо заменяет многоуровневый тернарный оператор

Тут всё лишь дело в привычке - но да - к тернарному оператору в императивных языках привыкли многие - и его, конечно, можно было бы добавить для упрощения перехода с других императивных языков - но это совсем не обязательно - и мне кажется, к концу века тернарный оператор вовсе отомрёт (в том виде, как мы его знаем)

Добавка.

Первый раз тернарный оператор проявился в императивном языке программирования Алгол-60 (1960) и это как раз было выражение вида "res := if o1 then o2 else o3". Но в таком виде в императивных языках он далее почти не фигурировал. Может быть вплоть до императивно-функционального ЯП Scala (2004).

Что-то подобное именно оператору появилось чуть позже в языке BCPL (1967):  res := (o1 -> o2, o3)

Ну а самый распространённый синтаксис тернарного оператора появился уже только начиная с языка Си (1972): res := o1 ? o2 : o3

Но, замечу, что в самом популярном (в 2022 году) языке Python тернарный "оператор" (выражение) только такой: res := if o1 then o2 else o3

А в Swift, Java, JavaScript применяется Си-подобный тернарный оператор

Но, замечу, что в самом популярном (в 2022 году) языке Python тернарный "оператор" (выражение) только такой: <...>

Ну нет же


res = o2 if o1 else o3

Век живи, век учись - спасибо что поправили

Вот вам - ещё один вариант синтаксиса - уже формально четвёртый в императивных языках - а ведь ещё что-то такое бывает  res = if(o1, o2, o3) - привет от Visual basic .NET - а ещё такое бывает (оооочень редко) res = ?(o1, o2, o3)

Ну и разные вариации в функциональных ЯП.

Добавка.

В Kortlin запись "a = if (b == c) d else e" можно интерпретировать так

  1. Сначала срабатывает инфиксная функция else (более приоритетная чем if; захватывает левое и правое выражении) - которая получает на вход два лямбда-выражения - и объединяет их в новое лямбда-выражение - что-то типа { -> Pair<()->Unit,()->Unit>(d, e) } (вернее тут будет, конечно обобщённый тип результата) - т.к. фактически пакует два выражения в кортеж, который затем пакуется в анонимную функцию с замыканием аргументов исходных выражений.

  2. А затем уже применяется функция if с двумя входными параметрами - один булевый, второй (правый) принимающий на вход лямбда-выражение с типом результата функции else (этот тип - лямбда-функция)

  3. Так как это лямбда-функция на конце - то этот аргумент может быть пропущен при вызове, с захватом следующего (справа) блока кода - являющегося результатом функции else (тут я немного луквалю - т.к. у Kotlin тут есть нюансы реализации логики, ограничивающие прямую реализацию такого подхода на языке Kotlin - но компилятор может сделать для себя исключение)

  4. Ну а далее внутри функции if проверяется условие и в зависимости от его результата распаковывается и вызывается то или иное выражение и возвращается его результат.

Далее привожу примерный код с некоторыми уточнениями и допущениями:

  1. Упаковка в кортеж Pair<()->T,()->T>)(f1,f2) осуществляется встроенной в Kotlin инфиксной функцией f1 to f2 (в коде ниже будет написано "this to f2")

  2. if и else заменены на If и Else соответственно, т.к. являются ключевым словом (компилятор же ключевые слова может обрабатывать как ему будет угодно, но пользовательском коде ключевые слова как идентификаторы запрещены)

  3. Kotlin не подхватывает результат функции Else как лямбда-функцию, которую можно было бы захватить справа - поэтому закомментированная строка не компилируется (но внутри компилятора это может быть реализовано в виде исключения - каких-то логических препятствий для этого нет - всё корректно определено)

  4. Поэтому передаю этот аргумент явно значением второго параметра функции If

  5. По ряду синтаксических нелогичных ограничений языка Kotlin пришлось ввести вспомогательный обобщённый псевдоним типа "Fn = ()->T" (и позже это всё-таки ещё "встанет колом")

    Вот рабочий код ниже:

typealias Fn<T> = ()->T 
fun <T>If(c : Boolean, b : ()->Pair<Fn<T>,Fn<T>>): T
{
    if (c) 
    	return b().first()
    else 
    	return b().second()
}
infix fun <T>Fn<T>.Else(f2 : Fn<T>) = { ->(this to f2}

fun main() 
{
    //val r = If(false) {println("f1"); 1+2}Else{println("f2"); 1-2};
    val r = If(false,({println("f1"); 1+2}Else{println("f2"); 1-2}));
    println(r)
}

Немного подумав - предлагаю вторую реализацию - уже с неявной передачей упакованных выражений во второй аргумент функции If:

typealias Fn<T> = ()->T 
fun <T>If(c : Boolean, b : ()->Pair<Fn<T>,Fn<T>>): T
{
    if (c) 
    	return b().first()
    else 
    	return b().second()
}
//infix fun <T>Fn<T>.Else(f2 : Fn<T>) = { -> this to f2}
infix fun <T>Fn<T>.Else(f2 : Fn<T>) = this to f2


fun main() {
    //val r = If(false){({println("f1"); 1+2}Else{println("f2"); 1-2})()};
    val r = If(false){{println("f1"); 1+2}Else{println("f2"); 1-2}};
    println(r)
}

Вариант с закомментированными строчками (вместо парных незакомментированных) тоже рабочий - но вызов явно выглядит хуже - но, может конфигуратор поступает так - тут другой возвращаемый тип у функции Else - без запаковки в анонимную функцию - которая образуется уже в виде явного Unit блока после вызова функции If - тогда этот блок захватывается компилятором и передаётся в качестве второго (правого) аргумента функции If.

Вот такое небольшое исследование того, как фактически (с точки зрения внутриязыковой логики) может быть устроен тернарный оператор в Kotlin. Тут, конечно, можно было бы исследовать дальше - например конструкции "val r = if (c1) exp1 else if (c2) exp2 else if (c3) exp3 else exp" а так же рассмотреть более сложный оператор when, а ещё напрямую заглянуть в исходники открытого компилятора Kotlin - но это уже явно потянуло бы на целую большую статью - написать которую я пока не могу.

Даже если в Kotlin всё устроено иначе, чем предположил я - то всё-равно, надеюсь приведённые мной выкладки будут полезны для понимания различных мощных синтаксических фишек языка, позволяющих быстро писать компактный, производительный и красивый код

Минуса говорят что тема эта не интересна - жаль :-(

Ну и в скале так же, и чо? Это не более чем непривычно. Хотя еще как посмотреть — если у if есть результат, это как раз наоборот логично, и привыкнуть к этому можно быстро.

Это сделано специально, чтобы операция тернарника не сливалась с кодом. Плюс есть компиляторные сложности, но их можно обойти.

Да там многое сделано специально. Специально for (int i = 0; i < n; ++i) удалили, специально классы по умолчанию нерасширяемые, специально static-методы и поля убрали.

Лично я еще ни одного собственного языка программирования не написал, и уверен, что этому всему была 1000 и одна веская причина, одна другой весче. Но жутко бесит утомляет, когда ты уже лед -дцать гладил кошку и она урчала, а тут только руку поднес, а она тебе внезапно человечьим голосом молвит: "допускается использовать только тыльную сторону руки, и да, не забудьте мизинец оттопырить, иначе я благим матом орать буду вместо урчания".

Возможно, еще через -дцать лет удастся привыкнуть и не придется сначала по привычке писать код как привык делать в C++, потом в JavaScript, потом Java (куда только кривая дорожка программиста не заводила), а затем спохватываться, удалять и писать "как тут принято".

Я хочу рассказать вам о новом языке программирования под названием Kotlin

Вы шутите или издеваетесь?


А не, вы просто перевели публикацию 2017го года...

Что в этом случае можно быть приравнено к "издеваетесь".

Раньше я предпочитал Java, но за прошедший год обнаружил, что кодирую на Kotlin при любой возможности

Я бы и про автора оригинала сказал, что он просто имеет узкий кругозор, и не знает например про скалу или груви. Да собственно и котлину уже 11 лет, в 2017 он был далеко не новым уже.

Я просто думаю, что все вот эти переводы (по качеству это кстати хорошо заметно — чуть нетривиальная тема, начинаются косяки) пишут люди, которые сами никогда близко не стояли ни к котлину, ни к любой другой теме. Ну переводчики это… просто переводчики. Хорошо если не гугло… И какие темы на самом деле интересны и актуальны, они в итоге не понимают. Не думаю что это сознательное издевательство, просто в этом процессе нет обратной связи как таковой. Вы посмотрите хоть на автора этого текста — 1.4к публикаций, и при этом 34 кармы (и 257 комментариев). Никому это качество текстов (из заказчиков автора) не нужно.

Тут не только перевод, статья с медиума, а на этом ресурсе в ТОПе как правило статьи предельно низкого качества с хайповыми заголовками, типа "Почему ты должен...", "X вещей, которые ты обязан делать в языке Y", "ХХХ мертв и вот почему.", и тд., ну а у переводчиков нет знаний оценить качество, переводят из топа и получается то, что получается.

А чем Scala интереснее по сравнению с Kotlin? Не подкол, просто вопрос.

Ну, прежде всего — это субъективное мнение… Я скорее имел в виду не что она интереснее (хотя в ней есть и такое), а что уже очень давно в этой же нише (языков для платформы JVM, если на то пошло) есть куча вариантов, а те кто при этом бездумно предпочитает Java — они зачастую просто не в курсе того, какие у них есть возможности.

Я бы сказал, что у них есть свои преимущества у обоих. Скала посложнее, но в тоже время мы вот пишем на Spark Shell, это по сути скала + спарк API, и получается как правило так, что эти сложности нам не видны вообще, а есть у нас в наличии более простая и чистая Java, где можно написать val a= «abcd», и никогда не нужно было указывать что это переменная/константа типа String, где можно написать Array(1, 2, ...).map{}, и не думать, что за тип у этой коллекции, и почему у нее вдруг нет .stream()?

Ну и груви примерно из этой же оперы. Литералы для мапов и списков, ламбды от рождения, DSL на раз-два, и все это уже 17 лет кажется. Синтаксически все проще и удобнее, а семантически доступно все тоже самое.

Новом языке?)) он с 2011 года существует. Статья прямиком из прошлого

Новый язык для переводчика и школы))

почему вы должны рассмотреть его для своего следующего проекта

я обычно прошивки для разных МК пишу. Мне точно надо зафеячивать туда котлин? С++ уже не в моде?

val в kotlin это переменная которая является неизменяемый, но лежащий в ней объект вполне может менять значения своих полей, то есть в отличие const не фиксируется на этапе компиляции

Не трожьте компаньонов - может синтаксис и не удачный - зато единственный вариант определения статических членов класса. Да и не так уж он ущербен такой синтаксис - просто дело привычки. В некоторых языках вообще нет статических членов классов - нужно только отдельно синглетоны определять для этого. А из компаньонов классов Котлина может ещё со временем раззовётся что-то более толковое!

Мне вот больше не понравилось, что все члены и классы по умолчанию закрытые - нельзя наследоваться и переопределять! Я понимаю, что это ради производительности. Но уж больно снижает гибкость разработки при использовании сторонних библиотек без исходников.

Или очень ограниченные кортежи

Ну и нет таких широких возможностей по раскрытию неограниченных параметров функций, как в Питоне.

Статья настолько свежая, что несколько пунктов уже завезли или в процессе завоза)

Меня забавляет что школа онлайн образования продвигая курсы, переводит статьи, вместо того чтоб со своими ведущими экспертами как написано на сайте, сообща написать новую техническую статью

Переводя статью 2017 года автор решил тонко обратить взор читателей на историю социа-демократического движения? Тогда при чём тут Хабр?

Что насчёт переносимости? Если я хочу запустить веб на основе приложения или наоборот. Здесь, наверное, java лучше. Или проекты на java не переносятся.

Что имеется в виду про переносимость? Взаимодействие с джавой работает в большинстве случаев хорошо. Есть косяки конечно, у меня как-то не получилось в котлине отнаследоваться от джава класса, кажется причина была в том, что котлин имплиситно вставляет гетеры/сеттеры и override джавовского гетера ломался, но точно не помню. Если под переносимостью понимается конвертация джава классов в котлин, то в Idea это выполняется одним кликом мыши. Не идеально конвертится, но руками потом можно поправить. Ну и с каждым разом команда Jetbrains эту конвертацию улучшает. Хотя перечитал ваш вопрос еще раз, какой-то бред написан, но раз уж настрочил я ответ, то запощу его

В C# почти все эти фишки добавили в новые версии языка - не нужно никуда переходить. Возможно и в Java добавят - так что бегать туда-сюда смысла нет, лучше подождать.

Очень жаль, что у компаний нет кармы. Иначе ее бы быстро спустили в минуса за подобный треш.

Какие реальные преимущества Kotlin перед Java, если отбросить синтаксический сахар?
Другими словами, что можно написать на Kotlin, чего нельзя на Java?

Что можно написать на Java, что нельзя написать на С++ или С, а что можно написать на них, чего нельзя написать на Asm

В современных ЯП в рамках одной парадигмы (хотя они сейчас как раз-таки становятся мультипарадигменными) всё так или иначе определяется синтаксическим сахаром и моделью выделения памяти и контроля ссылок - но если с памятью всё, в первую очередь, определяется средой выполнения и компилятором, то в рамках одного движка остаётся только удобство написания программ и удобство их тестирования и отладки - что, в итоге, и определят скорость и качество кодирования алгоритмов, и отчасти их производительность и надёжность (как составляющие качества). Так же есть некоторые современные тренды - ЯП развиваются - люди их изучают у ЯП идёт конкуренция за программиста - поэтому ЯП частенько тырят разные синтаксические фичи друг у друга - что приводит к их некоторой унификации и образованию некоторого обобщённого слоя общих семантических подходов. И чем консервативнее ЯП - тем больше он удаляется от этого слоя и тем более становится не интересным!

И ещё - сейчас императивные типизированные ЯП делятся на две группы

  1. Левая типизация как у Java , или Dart, или С++, или C#, или Perl / PHP

  2. Правая типизация как у Kotlin или Rust, или Go, или TypeScript, или Pascal

И у каждого подхода есть сторонники и противники (вот тут есть на хабре небольшой анализ). Но в целом сейчас тенденция в современных ЯП к переходу к правосторонней типизации. Вот такой заменой и является Kotlin для Java. Ну и в Kotlin ещё завезли более продвинутую модель ООП (в первую очередь со свойствами и с делегатами свойств) и "рефлексию" - вот, кстати, расширенных метаданных в Java библиотеках нет, и тут много взаимовытекающих ограничений.

(не уложился в таймаут редактирования написанного комментария - добавка к моему комментарию)

...взаимовытекающих ограничений (например отсутствие значений по умолчанию у функций; или при использовании дженериков)

С дженерик определениями тоже - куда удобнее при правосторонней типизации (дженерик определение слева, а его использование справа - читаем слева на право).

Так что я всецело за правостороннюю типизацию.

А ещё за правосторонние директивы и аннотации (ну или на выбор - по удобству слева или справа - оба варианта можно сделать допустимыми одновременно).

И вообще на эту тему давно хочу написать свою статью!

Но пока ЯП Kotlin нет в даже в 20-ке самых популярных языков программирования, по версии Tiobe, в 2022 году. Java на почётном 3-тьем месте. А вот, на первое неожиданно вырвался Python. А на втором - неожиданно находится язык Си. Даже второй прямой конкурент (после Java, в области клиент-серверной и мобильной разработке) как Swift находится на 16 месте. А Kotlin оф язык мобильной Android разработки и мультиплатформенный, а Swift - практически только инфраструктура Apple

Есть и другие рейтинги, равно как и более менее взвешенный подход к ним. Эппл, естественно, побеждает везде где участвует, но и Котлин не выглядит настолько безнадёжно насколько это кажется только по Tiobe.

Мне, по наивности конечно, кажется, что сейчас инициатива у Эппл которая фактически предлагает писать на Swift для Мака, iPad и бэкенда и забыть про всё остальное, с упором на «всё». На что конкуренты отвечают кроссплатформенностью, которая вынуждает их а) включать и платформы Эппл, так что Эппл в эту игру выиграть может а проиграть нет, и б) грызться между собой, так что как только Rust допускают в ядро Линукс, так Гугол кидается лепить Carbon.

И преимущество в этих условиях будет иметь не тот язык который лучше (кстати, даже вынужденная кроссплатформенность снимает аргумент «для каждой задачи свой», который я всегда считал придумкой маркетологов, ибо задача одна - записать обнаруженное способом понятным и человеку и машине), а тот, у которого лучше инструментарий. В случае Котлин это означает - подождём выхода Kotlin Multiplatform на релиз.

Оставаясь в рамках JVM, ничего нового вы не напишете конечно, что нельзя было бы на Java. Но котлин умеет в разные среды исполнения компилить (например в JS). Пожалуй только этим принципиально отличается.

Попиши на Джаве асинхронный код. С CompletableFuture и цепочками .then(). И так чтобы условий там в цепочках было побольше, циклов и т.п. Очень, очень быстро захочется нормальных корутин, и очень сложно будет вернуться назад на чистую Джаву. Это самое главное преимущество, не считая приятных мелочей вида null-safety, extension functions и т.п.

Подождите до легких потоков. Все эти фьютуры не нужны в 99% процентов случаев. Хватит обычного потока. Он удобнее прям со всех сторон.

Котлиновские корутины это абсолютное зло для любого развесистого проекта. Раздебажить гонку в таком коде занимает какое-то неприличное время. А посадить баг с гонкой легче легкого.

Все хорошо, только судя по всему после бурного успеха, Jetbrains стали типичной корпо и вместо того что бы фиксить баги в своем софте или добавлять важные фичи за которые любили раньше их ide , то сейчас с каждым новым выпуском добавляют всякую фигню, типо нейросеть теперь дописывает код за вас, совместное писание кода и т.д. А пофиксить баг, что в котлине во время дебага suspend функции нельзя нормальной пройтись по callstack и тебя будет кидать в .class файлы, а не в .kt или .java ? А добавить элементарную функцию в rider и resharper, раз вы поддерживаете blazor, возможность видеть только изолированные для данного компонента стили? Всегда все любили jetbrains за то что делалось программистами для программистов

Взгляните на Anko в качестве примера DSL, который призван улучшить разработку Android

Смотрим: ⚠️ Anko is deprecated. Please see this page for more information.

почему вы должны рассмотреть его для своего следующего проекта

А я только только Rust начал изучать(

Некоторые пункты, приведенные как фичи котлина, уже реализованы в современных версиях java. Некоторые пункты, приведенные как плюсы, выглядят сомнительными, а местами это вовсе вкусовщина.

persons
    .filter { it.age >= 18 }
    .sortedBy { it.name }
    .map { it.email }
    .forEach { print(it) }

Называть подобный код более читаемым и поддерживаемым очень спорно. Более того, почему-то здесь не упомянуто про неочевидный return из лямбд, который в отличие от java делает возврат из окружающей функции. А чтобы выйти из лямбды придется вбивать возврат с меткой return@label. И такой код они называют читаемым, спорно, но поверим.

Другой момент с null-safe. При работе с БД у вас многие поля будут nullable. И тогда привет огород из элвисов: ?. ?. ?. Может и нечастый кейс, но точно нередкий.

Самая важное в этом всем. Котлин завязан на инфру java, но при этом развивается своим путем и добавляет свои фичи. И чтобы профессионально использовать среду вам придется хорошо разбираться и в java и в котлине.

>Называть подобный код более читаемым и поддерживаемым очень спорно.
Где-то дело вкуса, да. Но в тоже время — это и котлин, и чистый груви, прямо вот без изменений. Ну разве что названия методов могут быть чуть другими — груви старше. И у такого стиля есть свои поклонники (и преимущества). Например, оно лучше компонуется.

У Groovy и Kotlin несколько разная модель типизации. Ну и Kotlin это не только JVM

Но большое влияние Groovy, Scala, C# на Kotlin не оспоримо!

Ну да. Про то что это не только JVM, я уже где-то тут написал — кто-то поставил минус, без аргументов. И да, они все конечно разные. Я про другое чуть-чуть — что задолго до котлина (скала же 2004 год вроде?) у тех кто был не полностью удовлетворен Java (а она тогда развивалась не в пример медленнее, чем сейчас) была куча возможностей. У них был выбор. Даже JYthon вполне пригоден к применению, а уж тогда и подавно был. Кложа, опять же. Есть варианты на любой вкус, и давно. И когда автор в 2017 говорит: «Ой, я тут котлин обнаружил», мне кажется он просто был нелюбопытен предыдущие годы )))

Ко-ру-ти-ны. Даже если бы были только они и интероп с джавой - УЖЕ нужно бы было переходить. А тут - нашелся пункт для свистоперделок типа when (которые приятные и удобные - но все же МЕЛОЧИ) - а для самого главного - корутин и асинхронности на их основе - не нашлось.

Пункты 3,4,8,10,13 — есть и в Java, причем некоторые из этих пунктов присутствуют в языке давно. Пункты 5 и 11 — я бы не стал торопиться называть преимуществами. Создаётся впечатление, что последняя версия Java, с которой знаком автор, это в лучшем случае восьмая.
Это статья 2017 года. Где-то так оно и было на тот момент.

То, что мертво, умереть не может

"Увечный астролётчик стал в позу и разразился речью, в которой призывал всё человечество поголовно лететь на планету Хош-ни-Хош системы звезды Эоэллы в Малом Магеллановом Облаке освобождать братьев по разуму, стенающих (он так и сказал: стенающих) под властью свирепого кибернетического диктатора."

Sign up to leave a comment.