
Комментарии 20
— Хочется поговорить о проблемных местах. Продолжая разговор про обратную совместимость: а было ли за годы работы над Kotlin принято какое-то значимое решение, о котором впоследствии пожалели, но было уже поздно менять?
— Да, бывало. Этот вопрос нередко задают, и у меня уже есть заготовленный ответ. На самом деле, мне надо почаще думать про это заново, но пока просто расскажу имеющийся ответ. Есть две наиболее сложных в поддержке фичи, про которые я жалею, что мы либо вообще их зарелизили, либо не подумали над ними в своё время побольше.
Одна — это делегирование классов, возможность имплементировать интерфейсы делегированием. Хорошо было бы, если бы мы не зарелизили это в своё время в 1.0 и взяли побольше времени на то, чтобы это подизайнить. В 1.0 у нас ещё не было понятия экспериментальных фич. В итоге получилась очень негибкая фича, и очень сложно как-то её развить. Мы в этой области не сделали никаких позитивных шагов за два года, потому что это попросту слишком сложно, она сопротивляется. И что с этим делать, пока непонятно, будем думать дальше, как сдвинуться с этой мёртвой точки.
И вторая такая же проблемная фича — это companion objects. Там развитие какое-то есть, но это тоже слишком сложная в поддержке история, потому что много завязок в разные места. Было бы здорово, если бы мы в своё время потратили побольше времени на дизайн этой фичи. Но мы не догадались, что это такая серьёзная точка риска, и не вложили туда больше ресурсов.
Ещё есть доклад про заимствованные из других языков идеи
Однажды я писал примерно вот такой код:
val handler = Handler()
val action = { println("Hello world!!!") }
handler.post(action)
handler.removeCallbacks(action)handler.post(Runnable) добавляет Runnable в очередь на выполнение, а handler.removeCallbacks(Runnable) удаляет Runnable из этой очереди. Судя по коду, строка Hello world!!! не будет напечатана, но она печатается. В чем же дело?
Оказывается лямбда имеет тип Function0<Unit>, а handler.post(Runnable) и handler.removeCallbacks(Runnable) принимают в качестве аргумента Runnable, и котлин для удобства и бесшовной интегреции с Java оборачивает лямбду в Runnable и получается, что в очередь добавляется один Runnable, а удаляется другой.
Для того, что бы исправить ситуацию, нужно добавить Runnable перед лямбдой, вот так: val action = Runnable { println("Hello world!!!") }. Теперь action имеет тип Runnable и ничего не оборачивается и корректно работает.
Получается, что в данном случае проблема в том, что компилятор много на себя берет и скрывает часть своей работы от программиста с расчетом на то, что этот сахар ничего не сломает.
У меня, честно говоря, в голове не очень укладывается: если я вот прямо сейчас начну делать язык программирования, да ещё и "наберу команду" — моих сбережений хватит в лучшем случае месяца на 3 работы. Откуда у Бреслава такие ресурсы?
КДПВ почему не с Kotlin? ;)
О, удачный код для обсуждения Котлина. myself в данной функции имеет тип Person?. Хотя скорее всего подразумевается, что Я уж точно существую. Как идеоматичнее быть в данном случае? Не хотелось бы использовать оператор !!, т.к. его использование расслабляет и плявляется соблазн использовать его повсеместно, что сводит на нет все плюсы котлина с точки зрения null безопасности. Можно написать ?: return, но это так же плохо как и пустой блок catch при обработке исключений. Наверное правильнее было бы бросить исключение: ?: throw IllegalStateException("Myself is not exists?!"), но не слишком ли много писанины ради ситуации, которая никогда должна случиться?
Кстати, если не менять код, то we будет иметь тип List<Person?>, что выглядит так же странно.
Все так, если бы не слишком важен был бы эксепшен — я бы просто использовал first.
Return может иметь смысл в зависимости от контекста.
Ну и самый общий случай это кидать после элвиса свой "бизнес" exception.
Делать методы которые принимают Person? в данном случае конечно не стоило
throw IllegalStateException(...) можно записать короче — error(...). Функция именно это исключение и бросает
Разве что после Java не хватает тернарного оператора.

Мучают ли Андрея Бреслава ошибки в дизайне Kotlin, которые уже нельзя исправить// Мы обречены #6