Pull to refresh

Comments 30

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

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

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


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

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

UFO just landed and posted this here
Если я правильно понял что вы пытаетесь сделать, то с котлином всё ок — это вы пытаетесь сломать концепцию неизменяемых значений.
val не должен меняться => 2 доступа к одному val должны возвращать одно и то же значение.
Тогда со всем чем угодно ок — просто некоторые пытаются сломать концепцию использования.

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

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

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

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

И?


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

UFO just landed and posted this here

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


Бесит то, что Котлин весь такой модный и форсит иммутабельность (что классно), но понять, что объект реально 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 строк) будет сложно
Sign up to leave a comment.

Articles