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

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

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

По поводу вложенности — полностью с Вами согласен.
Многократно вложенные функции помогают в билдерах. Яркий тому пример — Anko

Самая дичь, с которой приходится жить — это возможность переопределить get() у val и возвращать значения динамически, что нехило ломает концепцию неизменяемых значений и иммьютабилити в принципе :(


val a: Int
  get() = Random().nextInt()

Особенно печально, когда val определен в интерфейсе и ты не знаешь, пока не заглянешь в реализацию, immutable этот val или нет.

НЛО прилетело и опубликовало эту надпись здесь
Если я правильно понял что вы пытаетесь сделать, то с котлином всё ок — это вы пытаетесь сломать концепцию неизменяемых значений.
val не должен меняться => 2 доступа к одному val должны возвращать одно и то же значение.
Тогда со всем чем угодно ок — просто некоторые пытаются сломать концепцию использования.

Ээ, я ничего не ломаю, язык позволяет так делать, а нам приходится с этим мириться.

Не то чтобы мы от этого страдаем. Мне кажется предположение о неизменяемости само по себе неправомерно во многих случаях, например `List.size`.

Было бы гораздо приятнее иметь что-то вроде readonly var для таких случаев, а val оставить полностью иммьютабл

О боги!
Я не мог правильно прочитать сообщение, на которое ответил — я просто представить себе не мог, что в каком-то языке так можно делать.
Это же ужас!
Спасибо за пояснение.
Нет, я знал, что в котлине не уважают иммутабельность (те же их билдеры не могу существовать без мутабельности, что меня удивило при разборе HTML Builder), но что всё настолько запущено я не предполагал.
В чистой Java какой-либо геттер не обязан каждый раз возвращать одно и то же, даже если у него нет сеттера. (Если только это явно не сказано в документации). Так что неизменяемость для val только в том смысле, что нельзя что-то изменить снаружи операцией присваивания этому полю.

И?


В Kotlin val часто работает как final поле в Java, вот final в таком случае оказывается более строгим, чем val, это и печалит.

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

И? Я это понимаю :)


Бесит то, что Котлин весь такой модный и форсит иммутабельность (что классно), но понять, что объект реально immutable невозможно без чтения исходников/байткода. В Java это очень просто — public final поле это гарантирует (unless reflection). Подсказка со стороны IDE была бы очень не лишней (пойду тикет заведу).

Ну и зачем было делать этот it? Добавили проблему, теперь пытаются решить.

Не совсем согласен, что it бесполезен и является проблемой. Для простых лямбда-функций она позволяет компактно записать ваше намерение. На официальном форуме приведен очень показательный пример, с которым я полностью согласен:

// Намного лучше читается так, почти как английский текст
(1..100).filter{ it > 50 }.map{ it * 2 }
// Хуже читается, появляются доп. символы
(1..100).filter{ x -> x > 50 }.map{ x -> x * 2 }

Здесь it является плейсхолдером, как в Скале, типа как _ * 2 возвращает анонимную функцию с одним параметром. Плохо, что во вложенных функциях остается возможность сослаться на не тот if.

Возможности сослаться на `it` уровнем выше нету, переменная полностью экранируется.
Спасибо за статью, жду продолжения. Как раз планирую начать изучать Kotlin и такие статьи очень помогают.
Спасибо за статью, приятно почитать аргументированное и конструктивное мнение.

По поводу «проблем» которые не будут чиниться — то что затронуто в этой статье не больше и не меньше чем code-style. То бишь что тут чинить если это by-design заранее обдуманные случаи использования.

`it` в принципе не предназначен для callback-ов, в документации так и написанно — именуйте параметр кроме простейших случаев. Функция `let` действительно редко встречается в моей практике, но она незаменима для цепочек вызовов с функциями принимающими аргумент, например `mylist.let {LinkedList(it)}.filter {it > 0}`. В случае с `with` мне кажется очевидным что `getLatestComment()` не относится к `dbHelper`, но если это не так, то действительно лучше обойтись явными вызовами по старинке.

В общем, я согласен с автором что иногда неприятности встречаются в коде, но не согласен что это вина языка. Надеюсь давно обещанный продвинутый форматер решит подобные проблемы.
Для случая с with есть некоторое решение, не слишком элегантное, но запутаться не позволит:
fun f() {
    with ("string") str@ {
        with (123) num@ {
            println(this@str.hashCode() + this@num.hashCode())
        }
    }
}
Согласитесь, что приведенный выше код добавляет просто именованные константы, просто объявленные экзотическим способом. Намного лучше читается код, где эти константы объявлены в привычном виде:

fun f() {
    val str = "string"
    val num = 123
    println(str.hashCode() + num.hashCode())
}


Также использование данного именования явно указывает на проблему в коде (тот самый момент, когда говорят, что код «пахнет»).

Спасибо за то, что напомнили, что можно ещё и так использовать with =)
Ну, можно написать Очень Умную Функцию того же вида, что и with, тогда данный рецепт поможет. Опять же, DSL.
Спасибо большое за статью, очень здравый, но редкий подход к оценке языка не по тому, как он позволяет писать в хороших случаях, а по тому, как плохо и непонятно он писать позволяет.

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

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

Ну неееет. От груви он улетел гораздо дальше просто за счёт статичиской типизации

val user = response?.user ?: return
val name = user.name

как по мне но такие «ретурны» в коде могут быть очень малозаметными и в итоге код будет выполнятся иначе чем ожидает программист — да и найти такой «выход» в полотне кода (даже на 10 строк) будет сложно
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации