Такой провокационный вопрос задал реддитор nenemen в сабреддите Java:
«Я думаю о том, чтобы свой следующий проект сделать на Kotlin + Spring Boot, но мощь всенародной любви к Kotlin и одновременно ненависти к Java заставляют всё это походить на какой-то культ. Поэтому хотел бы услышать аргументы «против».
Мы в FunCorp в своё время сделали именно такой выбор в пользу Kotlin. И сегодня соотношение Java/Kotlin у нас составляет примерно 20 на 80, продолжая уменьшаться при каждом удобном случае. Поэтому ответы на этот вопрос меня заинтересовали, и я стал листать секцию комментариев. Там наткнулся на реплику реддитора rzwitserloot, которая мне показалась настолько взвешенной, многосторонней и рациональной, что я захотел поделиться ей с нашей командой, а заодно и читателями Хабра.
Далее перевод его аргументов.
Причины использовать Java вместо Kotlin
Kotlin более проприетарный. Например, изрядное количество подробностей внутренней работы kotlinc скрыто внутри сгенерированных файлов классов, представляющих из себя аннотации
@Metadata
с бинарными данными (байтовыми массивами, разрешёнными в аннотациях) внутри. Насколько мне известно, эти данные не описаны ни в каких публичных спецификациях. Также многие типы в Kotlin жёстко закодированы. Это вполне утилитарный подход, но он означает, что без IDEA (автор, видимо, имел в виду JetBrains — компанию-разработчик языка Kotlin и серии IDE для работы с разными языками программирования — прим. переводчика) Kotlin немедленно умрет. Конечно, это мелкая придирка, но, возможно кому-то этот недостаток открытости будет важен.Есть ощущение, что и сообщество, и IDEA продвигают Kotlin так, будто это Java, но без уродливых нашлёпок. Но что из этого следует? Останется ли Kotlin языком, который «чрезвычайно легко освоить, если вы уже знаете Java» и «так похож на Java, что вы можете взаимозаменять Java и Kotlin, а также вызывать одно из другого почти без усилий» в обозримом будущем (в этом случае я вижу проблемы, о которых расскажу ниже)? Или это был способ первоначальной популяризации и роста пользовательской базы, чтобы быстро заполучить сразу кучу Java-разработчиков и дать им возможность постепенно переводить свой код с одного языка на другой шаг за шагом, используя совместимость вызовов и двойную компиляцию? В этом случае к будущему языка тоже есть много вопросов. Мне кажется, что ребята, делающие Kotlin, думали, что оба варианта верные, но на самом деле они взаимоисключающие. Если попросить людей, которые понимают в Kotlin больше моего, объяснить, почему два следующих варианта неверны или не приведут в будущем к проблемам, то сначала решите между собой, что такое Kotlin и для чего он предназначен.
Если Kotlin всегда будет «как Java, только лучше»
Это реальная проблема. Лучше всего объяснить её на примере новой фичи языка.
Все фичи Kotlin делятся на три категории:
Что-то, что уже было в Java, когда Kotlin только проектировался. Тогда Kotlin берёт знакомые Java-разработчикам конструкции, и либо следует им дословно, либо делает по-своему, исходя из своих соображений «что такое хорошо». Кстати, перестановка местами типа и имени переменной или отказ от точек с запятой мне не кажутся хорошими идеями. Но текст и так довольно длинный, плюс это в изрядной мере личные предпочтения, так что не будем об этом.
Что-то, чего в Java не было и нет до сих пор. Они решили, что это нечто важное и сделали полностью по-своему.
Что-то, чего в Java раньше не было, но теперь появилось. Если Kotlin очень повезло, то в Java это сделали достаточно похоже, и разработчику в процессе переучивания с Java на Kotlin это не создаёт проблем. Но что, если это не так?
Суть в том, что со временем всё больше и больше фич Kotlin будут попадать в третью категорию, и поэтому подход «как Java, только лучше» — обречён.
Приведу пример: присвоение типа конструкцией instanceof
. Когда она появилась в Kotlin, в Java такого функционала не было даже в проекте: не было ни JEP, ни постов в блогах или рассылках (например amber-dev@openjdk.net).Такое поведение instanceof
решает типичную задачу: проверить, принадлежит ли переменная к подходящему классу, и если да — то работать с данными в переменной с учётом этого.
В Java вплоть до 14-й версии это выглядело так:
if (x instanceof String) {
String y = (String) x;
System.out.println(y.toLowerCase());
}
В Kotlin сделали примерно так:
if (x instanceof String) {
// теперь x имеет тип String!
System.out.println(x.toLowerCase());
}
Но в Java версии 16+ стало так:
if (x instanceof String y) {
System.out.println(y.toLowerCase());
}
Получается, что оба языка имеют способ обработать описанный сценарий, но разными способами. Я уверен, что если бы мог вдавить огромную кнопку «сброс», разработать Kotlin с нуля и снова выпустить сегодня бета-версию, то в Kotlin было бы сделано так же, как сейчас в Java. Учитывая, что синтаксис Java более мощный: мы можем сделать с ним намного больше, чем просто «проверить тип» (например, «деконструировать» типы-значения). Нам даже не нужен блок кода, а можно написать прямо так:
if (!(x instanceof String y)) return;
System.out.println(y.toLowerCase());
В целом, следующие несколько релизов Java расширяли этот принцип, добавляя много типов присвоения.
Теперь Kotlin должен сделать выбор:
Всё сломать, убить старый способ и переделать «как в Java». Это будет катастрофой, и потому крайне маловероятно. Такой вариант сломает огромную кучу чужого кода и навсегда подорвёт доверие к языку. Кому нужен инструмент, который будет ломаться каждый год или два?
Оставить всё как есть. Это значит, что аргумент «перейти с Java на Kotlin легко» будет всё слабее и слабее с каждым новым релизом и новой фичей Java.
Оставить всё как есть и добавить новый синтаксис. Звучит хорошо, но это значит, что с каждым своим релизом Kotlin будет накапливать вдвое больше плохих решений, чем Java. Со временем Kotlin превратится в ужасную разбухшую помойку формата «куча-способов-сделать-одно-и-то-же». Это приведёт к тому, что изучать Kotlin будет сложнее, а пользы это не принесёт.
Более хитроумное, но сложное решение. Например, сделать оба варианта, но исходный объявить устаревшим и через какое-то время удалить. Это означает, что Kotlin навсегда останется в тени Java без единого шанса оттуда выбраться.
Ни один из этих пунктов не кажется хорошим. Что приводит к более позитивному варианту номер два: начать отходить в сторону от синтаксиса Java. Отсюда следует:
«Как Java, но лучше» было способом получить первоначальное ускорение и пользовательскую базу
Часики тикают. Java не стоит на месте, а значит через год или три пропасть между ними станет достаточно глубокой, чтобы Kotlin перестал быть «как Java, но лучше». Он станет совершенно другим языком.
Это не худший вариант, но количество историй успеха новых языков программирования (видимо, автор имел в виду языки, работающие в JVM — прим. переводчика) исчезающе мало. Scala, например, практически мертва. Конечно, она собрала изрядно хайпа, на неё перешёл Twitter, организовал кучу классных митапов для разрабов, и… на сегодня у Scala меньше пользователей, чем было тогда. Это подтверждается инструментами типа TIOBE, которые оставляют желать лучшего в части точности, но давайте будем честны с собой: набирает ли Scala обороты в последнее время? Fan/Fantom зашёл в абсолютный тупик, Groovy не подаёт признаков жизни настолько, что Gradle пытается диверсифицироваться от него подальше. JRuby и Jython появились и исчезли, в том смысле, опять же, что никого они не вдохновили.
Конечно, нет никаких доказательств, что все новые языки изначально обречены. Но с другой стороны, это некая ситуация «по умолчанию». Прямо сейчас Kotlin оседлал волну успеха, но со временем жизнь его будет тем тяжелее, чем шире будет зазор между ним и Java, и чем сложнее будет преодолеть этот зазор.
Ему придётся опираться только на себя и перестать рекламировать доступность всех преимуществ Java и её экосистемы. Пример с instanceof уже демонстрирует, почему я думаю, что Kotlin не будет лучше Java: почти каждая новая фича, которая появилась в Java недавно или вот-вот появится (в смысле, имеет активный JEP и обсуждается в рассылках) выглядит более продуманной, чем любая фича Kotlin. Java развивается в сторону доступа к нативным 80-битным регистрам CPU сложных типов, сохраняющих производительность и требования к памяти как у примитивов, так и в целой новой парадигме программирования, основанной на присвоении типов и деконструировании значений.
[конец перевода]
От себя: очень хочется не согласиться с этим суждением, но в комментариях на Hacker News большинство контраргументов опровергаются. Например, поддержка со стороны Google — штука во многом политическая, которая в любой момент может прекратиться, когда тяжба с Oracle закончится. Да и дефицит внимания — характерная вещь для Google, пример Dart отбивает охоту делать на него ставку. Нативная поддержка null, которая греет душу любого котлиниста, легко заменяется в Java на обёртку из Optional.ofNullable
. Data-объекты могут быть заменены более богатым функционалом record
. Скорость компиляции, да и в целом производительность в Kotlin по сравнению с Java тоже оставляют желать лучшего.
Как думаете, сохранит Kotlin свою популярность через пять лет и почему?