Как стать автором
Обновить

Комментарии 36

интерференция типов
type inference != interference
вывод типов

Тоже кольнуло глаз.

@Data
@AllArgsConstructor
class Person {
    private String name;
}
...
val name = "John Doe";
val person = new Person(name);

и вроде как разницы уже и нет :)


а можно еще посмотреть код на Котлине когда у вас есть 20 пропертей в классе и надо одно из них убрать из вывода toString?

а можно еще посмотреть код на Котлине когда у вас есть 20 пропертей в классе и надо одно из них убрать из вывода toString?

Подобного нет и не планируется, так как идея data class — это покрыть 90-с-чем-то процентов типов для хранения данных. Если поддержать все 100% возможных вариантов (разрешить наследование и тд), то способ описания подобных классов будет настолько сложным, что люди будут бояться его использовать.


Зачастую статьи про сравнение Kotlin-Java содержат data class + небольшую мелочь, причем пропускается громадное число плюсов, которые упрощают "типичный проект", который пишется теми, кто готов изучить +1 язык программирования. Не любой, а именно "типичный". Я приведу несколько примеров (хотя список не исчерпывающий), которые упрощают проект:


data class SomeDto(val field1: Type1 = Type1.default, val field2: Type2 = Type2.default)

/*далее по коду*/

return SomeDto(field1 = Type1("custom data"))    

В коде выше есть значения параметров по умолчанию. Причем можно использовать не только константы, но и результат работы функций. И не надо добавлять кучу перегруженных методов.


@Service
internal class MyService(private val anotherService: AnotherService, settings: Settings) {
     private val parameter = settings.parameter

     fun doSomething() {
            return anotherService.do(parameter)
     }
}

В коде выше у класса MyService в конструкторе первый аргумент сразу присваивается полю, из второго вызываем один getter, создавая второе поле. Если Вы работаете со Spring'ом, то подобное будет едва ли не в половине сервисов. И не надо Lombok'а и прочих таких вещей.


class SomeDeserializer {
      private val mapper = jacksonObjectMapper()

      fun convert(data: String): MyObject {
             return mapper.readValue(data)
      }
}

Если язык может вывести и подставить тип — он это сделает. За счет инлайн функций, тип в процессе компиляции передадут десериализатору.


См. также тут пример того, как можно вытащить конструирование объектов в некоторое подобие shape классов.


Однако важно понимать: не факт, что все эти дополнения упростят произвольный проект на Java. Если команда старается писать write-only код, то на kotlin можно легко его сделать еще более запутанным. Или если в команде по какой-то причине есть ненависть к var, то с приходом Kotlin только разгорятся холивары. Если в команде есть любители завернуть длинную цепочку вызовов (чтобы функция выглядела как expression), то Kotlin развяжет им руки, что еще более ухудшит читаемость. Так что требуется определенная сознательность (иначе чтение кода будет начинаться с рефакторинга в идее, чтобы получить более-менее читаемый исходник).

Я могу наприводить примером с Ломбок, которые в Котлине не сможете сделать. Так же как и вы приведете свои. Те на самом деле позиции примерно равные.


который пишется теми, кто готов изучить +1 язык программирования.
И не надо Lombok'а и прочих таких вещей.

Для меня вопрос, почему вы считаете проект на нескольких языках как плюс. А использование Ломбок который не привносит ничего в рантайм и добавляется как одна зависимость в Мавене как минус.

Для меня вопрос, почему вы считаете проект на нескольких языках как плюс.

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


Ну и в проектах, где я участвовал, было море языков: dsl для Gradle, Sql для базы, shell скрипты для разных ОС. И это еще если нет С#/TS/JS для клиентского кода. Да и язык не такой сложный, чтобы можно было бы оправдать идею "не будем еще и на нем кодить" (как мне кажется).


Основной мой посыл выше — плюсы Kotlin отнюдь не заканчиваются на data class. Однако в статье именно такой посыл, будто бы язык, на который много кто переходит, просто представляет всего лишь Java+Lombok. Что крайне далеко от истины.

Ну и в проектах, где я участвовал, было море языков: dsl для Gradle, Sql для базы, shell скрипты для разных ОС.

Это вы уже перекручиваете. так можно сказать и JSON и YAML записать в языки :)
Cмысл на бэкенде с ЖДК 11 или 14 использовать Котлин для меня не понятен. Под Андроид это да — must have. А бэкенде нет смыла — тк особо не укоротишь ничего и отовсюду торчат уши стандартной джавы от используемых библиотек. Просто так взять и хибернейт засунуть в корутины не получится.


Да и язык не такой сложный, чтобы можно было бы оправдать идею "не будем еще и на нем кодить" (как мне кажется).

Дело не в сложности, а в целесообразности.


Основной мой посыл выше — плюсы Kotlin отнюдь не заканчиваются на data class.

А где он делает действительное что то уникальное? Кроме давайте сократим на пару символом джава код. Используя ЖС(какой нить Vue+Node) я понимаю плюсы такого подхода, берем Раст и тоже понятно, даже Го обладает уникальными свойствами ради которых их можно использовать. А Котлин как не кручу, ну не вижу смысла.

НЛО прилетело и опубликовало эту надпись здесь

Легковесные потоки? Null-безопасность? Функции-расширения? Свойства (в Java есть только псевдо-свойства)? Перегрузка операторов? Про лаконичность и функциональный уклон уже писали.


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


Kotlin, несмотря на все свои плюсы, еще молод. Переходить на него "просто потому что" немного странно. Начать новый проект — почему бы и нет?


Сам не так давно начал работать с Groovy (параллельно с Java) — несмотря на то, что есть очевидные плюсы, многое из того, что использую в Java, не хватает. Что-то непривычно и не нравится (динамическая типизация, замыкания вместо уже привычных лямбд, статическая компиляция по желанию).

Э-э-э Groovy и Kotlin это немного разные вещи.
То что нет в Kotlin, и есть в Java. Это все равно есть в Kotlin.
Т.к. интероперабельность Kotlin с Java ну очень прозрачная.
И да. Плюшки 14 Java есть в Kotlin на JVM 1.8.
Kotlin позволяет в «кровавом Ынытпрайзе» иметь плюшки последних версий Java. :-)
А где он делает действительное что то уникальное? Кроме давайте сократим на пару символом джава код.

Type-safe билдеры для описания древовидных структур. Котлин первый язык, который такое позволяет, и благодаря этой возможности Google сейчас разрабатывает Jetpack Compose.
Ещё одна интересная парадигма, ставшая возможной — контекстно-ориентированное программирование. Об этом писали на хабре, она же активно применяется в математической библиотеке, разрабатываемой автором статьи.
Другой пример, который мне лично очень нравится — это различные high order функции для работы с ресурсами. Как пример, функция use из стандартной библиотеки. Это функция расширение для AutoCloseable, которая принимает лямбду для работы с открытым файлом. Функционально похоже на try-with-resourse, разве что исключения не обрабатываются. С точки зрения кода это даже выглядит, как полноценный оператор. Но это функция (!). И очень похожую функцию авторы языка добавили в Kotlin/Native — memScope.
fun allocationExample() = memScoped {
val a = alloc() // Выделенная тут память будет автоматически очищена после выхода из области видимости
}

А использование Ломбок который не привносит ничего в рантайм

Интересно знать, почему это он не приносит, чем он отличается от stdlib?
Кому-то нравится язык, кому-то нет, один бессмысленный холивар здесь

Потому Ломбок генерит бойлер плейт байткод на этапе компиляции.

Lombok это препроцессор аннотаций, который, будучи в classpath, автоматически распознается и используется Java компилятором (javac). Ничего в рантайм при этом не привносится. Погуглите интерфейс "javax.annotation.processing.Processor"

Для преобразования данных я использую функции расширения

Например так:

fun String.toMyObject(): MyObject =
        ObjectMapper().readValue(this, MyObject::class.java)

а можно еще посмотреть код на Котлине когда у вас есть 20 пропертей в классе и надо одно из них убрать из вывода toString?

Например вот так:
data class Class(val field1: String, val field2: String) {

    override fun toString(): String {
        return field1
    }
}
НЛО прилетело и опубликовало эту надпись здесь

Один фиг это все очень неявная магия

Большинство кода который в статье автоматически генерируется IDE и его генерация не особо мешает. Я не думаю что люди набирают на столько много строк текста в день что данные примеры ускорят разработку. Корутины на мой взгляд выглядят интересно. А так пробовал писать сервисы для дев окружения но переводить/начинать что то серьезное смысла не нашёл.

Интересно, почему nullability, заставляющая думать о том, где могут возникнуть нули, это хорошо, а отсутствие new подаётся как плюс? Ведь это будет мешать начинающим разработчикам чувствовать места, где выделяется память.

А где она там не выделяется?

Она-то выделяется, просто теперь нет слова new, обозначающего создание объекта.

А зачем оно? Ладно в плюсах была разница, где создавать, в куче или на стеке, но тут то зачем оно.

Кстати, вот про такой минус я вообще первый раз слышу. Что-то новое. Однако зачем заставлять писать новый и новый текст ради того, чтобы помочь немногим новичкам (и показать им, что здесь выделяется память)?


Если в Java вы пишете new XXX, то не факт, что память выделится. Запросто придет оптимизатор и создаст объект на стеке.
Если в Java вы делаете foreach, то создается итератор. Однако, см. пункт выше — он может выделиться на стеке.
Если в Java вы создаете лямбду, то в зависимости от ситуации, она может или быть создана или одна на класс, или одна на тип, или одна на метод, или же одна на вызов, а потом придет оптимизатор, ну и дальше известно. В Kotlin еще есть inline функции, которые просто встраиваются в вызывающий код, а потом лябмда не пойдет в кучу (её компилятор просто встраивает). Как пример — все методы по коллекциям. Кстати, эту фичу не покрывает связка Java + Lombok, а потому её любят исключать при сравнении Kotlin vs Java.
Если вы используете int/Integer, то у вас может происходить боксинг/анбоксинг. Но не всегда, потому что Java создает синтетические невидимые методы (по сути — перегрузка), которые позволяют уменьшить число перемещение в кучу и обратно на стек.
Если в Kotlin вы используете suspend, то на почти каждый вызов метода создается объект в куче. Однако компилятор языка иногда оптимизирует вызов и обходится без этого. Если в Java вы используете CompletableFuture/Mono, то вы так же будете создавать кучу объектов, см. мой пример с лямбдами.
Ну и вспомним фабрики (по сути, тоже создают объекты), разного рода невидимую инструментацию и пр.


В общем непонятно, почему так необходимо писать new перед созданием новых объектов.

В общем непонятно, почему так необходимо писать new перед созданием новых объектов.

Ну вообще, важно не столько, что память выделяется, сколько то что это объект, а не функция. Да, обычно функцию начинают с маленькой буквы, а класс с большой, но вот кто-то перепутает и напишет наоборот. Как бы завязываться на код стайл — не очень надежно.

Вот можно навскидку сказать, что продойдет в этом коде при вызове функции B (подозреваю упадет при компиляции, но не уверен)?

class A{
    fun A(): String {
      return "World!";
   }

   fun B() {
     println("Hello " + A()); 
  }

  fun toString(): String {
      retrun "Alien!"
  } 
}
Да, обычно функцию начинают с маленькой буквы, а класс с большой, но вот кто-то перепутает и напишет наоборот.

Если в проекте нет detekt или аналога, то у меня сначала будут вопросы к отвечающим за проект (тимлид, архитектор, менеджер, "лидер проекта" — титул не особо важен).
Если программист пропустил подсказку из идеи "функция названа неправильно", то это уже маркер того, что мы рано начали спорить о языках, и нам надо вернуться сначала к основам.
Если код получается слишком неоднозначный, в стиле каскада apply, каждый из которых вбрасывает новые методы, то я бы посоветовал просто отрефакторить код, а не зазубривать приоритеты компилятора.


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


Мозг человека может обрабатывать ограниченное число объектов. А потому, функция, класс, проект и т.д. не должны быть сложнее некоторого порога, чтобы "наиболее вероятный разработчик смог её осознать за определенное время". Говоря другими словами: каждый блок проекта не должен быть сложнее, чем некоторое N. Оно разное для разных людей, кстати.
Ну то есть если мы будем для каждой функции расписывать конвенцию вызовов, то мы потратим ресурсы, а значит не сможем описать сложную логику. Или же опишем сложную логику, однако коллега (да и мы в будущем) не сможет быстро осознать, что тут происходит.
Как следствие — если мы хотим описать сложную логику, нам необходимо писать такой код, который потребует меньше всего отвлекаться на техническую составляющую:


  1. Если мы ходим не забывать корректировать код после изменений API, нам необходима строгая типизация. Иначе, вместо обновления логики, мы будем скорее тратить время на поиски того, кто бы где не упало. Или нам придется занимать память в голове, чтобы всё это помнить.
  2. Если мы хотим в будущем добавлять новые типы, которые сможет кто-то другой обрабатывать, то необходимо использовать паттерн visitor или sealed классы. Однако паттерн визитор несет в себе дополнительную сложность в виде хитрой сигнатуры и обилия кода, а значит sealed классы предпочтительнее.
  3. Если мы хотим сильнее сконцентрироваться на бизнес задаче, то нам необходимо так работать с памятью, чтобы вообще не отвлекаться на неё. GC, например, прекрасно здесь поможет. А вот расстановка new наоборот добавляет мусор.
  4. Если мы хотим тратить меньше времени на новый стиль отступов и пр., нам необходим style guide в проекте, который просто завалит билд, если всё очень плохо.
  5. Если мы не хотим помнить про хрупкие части проектов, их надо просто покрыть тестами (обычно необходимы и unit test'ы, и интеграционные).

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


Еще интересное следствие — если в проекте практически часть людей быстро всасывают знания о новом языке программирования, однако другая часть соображает медленно, то команду лучше раздробить, чтобы не мучать ни одну из её частей.


Важно: то, что я написал выше — это лишь моё обоснование тому, что код из примера просто некорректен. Оно, скорее всего, содержит белые пятна и неоднозначности, а потому лучше всего смотреть на всё это крайне скептически.

Как раз из того что мозг человека имеет свойства тупить на ровном месте — четкие маркеры работают лучше нечетких. Представьте, что с кодом работает человек после ночного дежурства в блокноте на сервере, где нет иде (было и такое в моей практике).

По идее лучший код с которым можно работать и в блокноте и на листочке бумаги. Встречалось когда разбирался в код имея только распечатку.

Я не говорю, что это большая проблема, скорее вкусовщина — но написать три буквы тоже не сложно. В целом это спор скорее табы против пробелов.
после ночного дежурства

Тогда надо отправить человека домой. Заставлять кодить в таких условиях — это верх непрофессионализма. К тому же этот пример лично для меня крайне нетипичный. Вы еще добавьте, что все сидят в военно-полевой палатке, а раз в несколько часов прячутся от артобстрела.


на сервере, где нет иде

Кодить на боевом сервере, да еще и на компилируемых JVM языках — это уже нарушение многих принципов разработки (code review? проверить тестами систему? А зачем нам такие неуверенные в себе работники, правда?). А, если не секрет, какая компания этим занимается?


По идее лучший код с которым можно работать и в блокноте и на листочке бумаги.

Нет. Это просто Ваше мнение. Моё: современный специалист увешан приспособлениями для эффективной работы. Строители пользуются высотомерами, бетономешалками, экскаваторами и кучей подобных вещей. Врачи пользуются скальпелями, аппаратами МРТ и так же кучей приспособлений. Так и программисты, в массе своей, имеют вменяемые компьютеры/ноутбуки, иначе глупо нанимать дорогих специалистов и вставлять им палки в колеса.


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

Врачи пользуются скальпелями, аппаратами МРТ и так же кучей приспособлений.

Но хороший ли врач, если он не сможет оказать первую очередь, скажем в ДТП, если у него под рукой не будет полного набора операционной и интернета?

потому идеи от «типичной разработки» просто перестают здесь применяться

Язык в идеале должен учитывать и нетипичные случаеи тоже. Ну вот знаю несколько человек, которые любят писать в vim'e или notepade+ и довольно нормально пишут. Нужно ли их переучивать на использование IDE, только потому что по другому языком пользоваться нельзя? Либо у человека в отпуске только планшет и доступ на гитхаб с кодом, а нужно решить срочную проблему?

то уже нарушение многих принципов разработки (code review? проверить тестами систему? А зачем нам такие неуверенные в себе работники, правда?)

Никто не говорит, что это основной способ разработки. Но если у клиента лег весь кластер и каждая секунда приносит огромные убытки, то сначала экстренная реанимация, а уже потом принципы и code review. Это не красиво — в моей практике случалось лишь раз (лет 10 назад). Компанию не скажу, профессиональная этика, тем более там вопрос был заказчике и его security политики.
Но хороший ли врач, если он не сможет оказать первую очередь, скажем в ДТП

В программировании аналогией будет "обновить конфигурацию", "настроить систему". Если нейрохирург не сможет удалить аневризму без оборудования, пользуясь лишь шилом, то у меня будут скорее вопросы к тем, кто ожидал такого от врача.


Ну вот знаю несколько человек, которые любят писать в vim'e или notepade+ и довольно нормально пишут. Нужно ли их переучивать на использование IDE?

Нет, просто если они не смогут эффективно работать на Kotlin из-за привязанности к своей среде, то, я думаю, им не стоит работать в команде, которая работает на Kotlin. Если люди принципиально не хотят работать в Windows, то им, я думаю, не разрабатывать UI приложения на Windows (рынок большой). Если для программиста действие "переучиваться на IDE" требует больше 1-2 дней, то у меня серьезные вопросы к квалификации и его, и тех, кто его держит в компании.


Язык в идеале должен учитывать и нетипичные случаеи тоже.

Нет. Языки разные, под разные нужды. Если вам необходимо делать частые ассемблерные вставки и руками управлять памятью, то я бы, например, вообще не советовал бы использовать JVM, .Net, Go. Для этого есть как минимум С/С++/Rust/Assembler. Если человек не умеет (или не хочет уметь) разрабатывать на них — то на рынке следует найти другого человека под задачу. В вузе мы писали на кучи языков, однако я сильно удивляюсь, когда взрослые опытные разработчики отказываются использовать разные языки под разные задачи.


Но если у клиента лег весь кластер и каждая секунда приносит огромные убытки

Тут надо не забыть уволить практически сразу "синьоров", "менеджеров" и выше. Если система не должна падать, то должно быть серьезное резервирование. Если его нет — меняйте отдел разработки, начиная сверху. В Bloomberg пишут код так, чтобы любой компонент мог быть откачен на предыдущую или предпредыдущую версию, потому что остановка системы принесет убытки. Если у вас в компании эффективный менеджмент не выделил бюджет, значит это точно не проблема уровня языка программирования. Если же в условиях задачи есть "постоянные фиксы в проде на горячую", то выбирайте Python/PHP. JVM стек здесь будет только мешать, он для другого.


В целом мы опять вернулись к предыдущему посылу: Kotlin поможет не всегда и не всем. Как и Rust, Java, C# и остальные языки. Однако типичный Java Enterprise проект он способен серьезно упростить, дав возможность вогнать больше бизнес-логики и пр.

А где сравнение размеров приложений «Hello world» и бенчмарки парсилок json-ов?
Пробывал котлин, с одной стороны какие-то вещи чуть проще (хотя многое уже и так есть в последней Java или покрывается Lambok'ом и аналогичными вещами), но на относительно слабом ноуте java проект собирается в Idea почти моментально, а стоит добавить kotlin классы все начинает ощутимо притормаживать. Плюнул и продолжил использовать в пет проектах java.

Да, как-то крайне невнятно.
Обе перечисленные особенности пришли из scala. И дата классы (которые в скале называются case class), и возможность создания экземпляра без new (хотя в скале там немного больше логики, чем просто "давайте больше не писать new").


А новое-то есть?)

Ну ведь котлин — это синтаксический сахар для тех, кто не осилил скалу. Скала была, есть, и будет гораздо более умным языком для компиляции в JVM байткод, но годы показали, что слишком умным. Толпе энтерпрайзеров, которые шагу без IDE ступить не в состоянии — чего бы попроще, но не такого многословного, как сама джава.


А новое-то есть?

Дык на выходе тот же самый байткод, чего принципиально нового вы ожидаете?

Поскольку инкапсуляция тут не обсуждается, то сравнение, я считаю, некорректным.
Что мешает написать такой код
Java
class Person {
    public String name;
}
Зарегистрируйтесь на Хабре, чтобы оставить комментарий