Comments
В этом Kotlin похож на JavaScript. Как в JavaScript, в Kotlin можно достичь того состояния, когда вы уже не знаете, что такое this.

*что-то вычеркивает в записной книжке
UFO landed and left these words here
Разница в том, что в JavaScript this определяется динамически, и без трассировки (хотя бы мысленной) не обойтись, а в Kotlin this можно вычислить статически, просто «на глаз» это не всегда очевидно. Иногда помогает расстановка явных скоупов this@Something
К сожалению, с практической точки зрения, эти «прикольные фичи», на самом деле – «долбанные ошибки дизайна».

Они есть во всех языках, но в некоторых для этого нужно сделать что-то невероятное.
А в Котлине, как показывает автор, на эти грабли можно будет наступить на каждом шагу :-(

Язык очень интересный, но складывается впечатление, что взяли все возможные фичи со всех языков и попытались все их уместить в один язык. В результате имеем такие вот забавные пазлеры.
«Неочевидная вещь» это не то же самое, что «долбанная ошибка». И да, другим языкам тут лучше помолчать, потому что у них заскоков бывает ещё больше.
Вы урезали контекст, изначально было: «Долбанная ошибка дизайна».
«Неочевидная вещь» – это проблема дизайна, т.е. – «Долбанная ошибка дизайна».

Тут хорошо подойдет аналогия с UI/UX: все должно быть максимально просто и очевидно. Если это не так, значит есть проблема. Язык программирования – это товар, а Программист – потребитель/пользователь.

Если Вы не согласны с этим утверждением, тогда ответьте на вопрос: почему каждый год выходят десятки новых языков и почему каждый раз, когда крупная компания выпускает свой язык, то подымается хайп?
Kotlin, Scala, Groovy, TypeScript, Elm, CoffeScript, Rust, Go, Swift, etc.

На сколько помню, целью Котлина было облегчение разработки и защита от глупых ошибок. А в результате одни глупые ошибки заменили на другие.
«Неочевидная вещь» – это проблема дизайна

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


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

Это суждение — следствие опыта разработки на котлине, или вы просто посмотрели пазлеры?

  1. Это не паззлер. Любой оператор?.. вернет nullable тип, это очевидно.
    Автора предложения об автоматической конвертации null в false надо вернуть обратно в яваскрипт и не выпускать до просветления.
  2. И это не пазлер. Для nullable типа могут быть методы расширения, это тоже очевидно.
  3. И снова не пазлер. Очевидное решение по скрещиванию null-safe языка с null-unsafe JVM.
  4. И опять не пазлер. Разница между методом и вызовом также очевидна.
  5. Первый реальный пазлер. С лямбдами это вечный вопрос и в каждом языке он решается по-своему.
  6. Не пазлер. Результат рекурсии немного предсказуем.
  7. Снова не пазлер. Ибо тезис "самое лучшее определение unit — это void." неверен. void — это не прагматизм, а костыль, заботливо перенесенный из си.
  8. Второй реальный пазлер и первый возможный претендент на ошибку дизайна. Правда сравнение с яваскриптом некорректно. В котлине значение this известно на этапе компиляции.
  9. Третий реальный пазлер на типичной проблеме приоритета и ассоциативности операций. Ошибкой дизайна не является, код паззлера выглядит плохо и имеет заведомо лучшую альтернативу.
  10. Не пазлер. Код сразу выглядит плохо, используя зависимость val от var. Конец снова предсказуем.
  11. Не пазлер, компилятор бдит, жаль только warning а не error.

Итоги: 3 реальных пазлера из 11, 1 (одна) возможная ошибка дизайна. В остальных случаях результат или очевиден сразу, или плохой код и выглядит плохо (для человека, а нередко и для компилятора), что и требуется для защиты от глупых ошибок.

Настоящий паззлер — это Пазлер 11. Все остальное — это ожидаемое поведение.

я не спец по котлину, но 9ый и 10ый пазлеры для меня выглядят как бага языка

Нууу…
Пазлер 9 — спорно. Можно рассматривать и так, и так. Возможно, JetBrains выбрали менее удобный вариант, но лично я предпочитаю использовать ключевое слово when, если веток больше чем 2.
Пазлер 10 — не баг, однозначно. Из доки следует, что делегат это объект с вот такими методами:
//на чтение
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        return "$thisRef, thank you for delegating '${property.name}' to me!"
}
//на запись 
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        println("$value has been assigned to '${property.name} in $thisRef.'")
}

У интерфейса kotlin.collections.Map нет таких методов, зато есть соответствующие экстеншн функции в файле MapAccessors.
То есть синтаксис объявления делегата по мапе не магия, которая от нас сокрыта, а вполне традиционный для котлина способ делегирования.
Люди, которые хотят автоматическое приведение Nothing к False, сами не знают чего хотят.
Отличная статья, но вот этот программистский новояз реально режет глаза — «пушит», «тулинг», «кейворд», и т.д. Неужели нельзя найти подходящие русскоязычные термины? Или вы боитесь что будет как в примере с «фу, знач, печать»? Спешу вас успокоить, вы только выиграете, если будете периодически чистить свою речь.
И чтобы лишний раз не стрелять себе в ногу, в примере 9 лучше писать с when:
fun printNumber(num: Int) {
    when {
        num < 0 -> "negative"
        num > 0 -> "positive"
        else -> "zero"
    }.let { println(it) }
}

Кстати, если в исходном примере встать на первый if и применить intention «Replace 'if' with 'when'», то картина почему всё так было, становится яснее:
    when {
        num < 0 -> "negative"
        else -> if (num > 0) {
            "positive"
        } else {
            "zero"
        }.let { println(it) }
    }

if (s?.isEmpty() ?: false) println(«true»)
Студия уже давно предлагает такое исправлять на
if (s?.isEmpty() == true) println("true")
Тут будет сравнение null == true,
null – это не булевый тип, т.е. эта запись недоступна (как в котлине, так и в джаве).
Такое сравнение допустимо: если одно из слагаемых будет равно null, то результат будет равен false. А вот null == null, ожидаемо вернет true.
Будет, но это сравнение двух значений типа bool? — вполне рабочее.
Изначально обсуждался следующий пример:
String s = null;
if ( s?.isEmpty() == true ) {
   // do something
}

В этом случае s?.isEmpty() вернет null.
Но null и true сравнивать запрещено.

null нельзя привести в boolean. А если это сделать – это ослабит типизацию, что повлечет ряд других проблем.
Изначально обсуждался следующий пример:
String s = null;

Это вообще не котлин.
Правильно как в статье:


val s: String? = null

А вторая строка — наоборот совершенно правильная


if ( s?.isEmpty() == true )

  1. s имеет тип String? (nullable String)
  2. s?.isEmpty() имеет тип Boolean? (nullable Boolean)
  3. Константа true принадлежит как типу Boolean, так и типу Boolean?
  4. Конкретный тип котлин выводит по контексту — слева от равенства Boolean?
  5. Соответственно справа будет тоже Boolean?
  6. Для этого типа можно сравнить true с null

Ссылка для проверки онлайн:
https://try.kotlinlang.org/#/UserProjects/2f15ok94p3k8lse1fj96t6apr0/2032nrf2rjpjvp11t1307onr7m

С Котлиным такой проблемы нет

Котлин это не фамилия :)
А вообще для kotlin-программиста большинство этих паззлеров не то что известно — это очевидное поведение языка :) Самый страшный паззлер 11, но и вкупэ с Intellij Idea страх перед возможностью напороться на паззлеры сам собой рассеивается.
UFO landed and left these words here
Only those users with full accounts are able to leave comments. Log in, please.