Pull to refresh

Comments 28

Спасибо за статью.

Проблема в том, что Kotlin компилируется в Java
Вы же, наверное, имели в виду генерацию Java-файлов annotation processor'ом из аннотаций в коде на Kotlin? Обычные исходники на Kotlin компилируются напрямую в байт-код, без трансляции в Java.

<...> если мы используем переданный в конструктор параметр, то он будет присвоен полю сразу, минуя переопределенный setter
Тут можно сделать что-нибудь в духе

class User(nameParam: String) {
    var name: String = ""
        set(value) { field = value.toUpperCase() }

    init { name = nameParam } // вызовется сеттер
}

Лямбда, вложенная в лямбду
Про такое, кстати, даже в документации (coding conventions) сказано, что если лямбды вложены, то у всех лучше явно писать все параметры вместо использования it.
Вы же, наверное, имели в виду генерацию Java-файлов annotation processor'ом из аннотаций в коде на Kotlin? Обычные исходники на Kotlin компилируются напрямую в байт-код, без трансляции в Java.

Да, аннотации в коде на Kotlin. Ещё раз уточню вопрос и поправлю статью
Тут можно сделать что-нибудь в духе

Я пробовал похожий вариант. В моем варианте поведение поля остается прерогативой поля, а не конструктора. Если таких полей несколько, а класс большой, то это начинает играть роль.
  1. Код, понятный только посвященным

Очень хорошо ложится, кстати, если не знать java при изучении kotlin (в моём случае — scala).
Типичная "функциональщина".

Лаконичность кода на языке K это не столько свойство языка K, сколько умение программиста четко и ясно выражать свои мысли вне зависимости от языка. Даже на Java можно писать коротко и понятно (если уметь). А если дать правильному джависту в руки C...


В последнее время читаю очень много кода на Kotlin. И скажу вам, Котлин, там где я его вижу ни разу не лаконичен. Почему? А потому что пишут на нем как на Java. С таким же страшным форматированием. И Scala не лаконична в неправильных руках. Так что если говорить о преимуществах и недостатках. Да, получается короче, но не очень. И не факт, что те 8500 строк которые вы имеете в проекте, нельзя приравнять к 8500 строкам кода на Java.

Согласен, проблема в головах. Но даже если просто везде, где нужно, добавить setter-getter, toString, equals и hashcode, которые мне достались бесплатно, то код разрастется где-то на треть.
Эмм, лаконичность в К конечно есть, как и в APL, но я думаю что большинство людей на Хабре сходу не скажут вам даже приблизительно, что делает выражение 2_&{&/x!/:2_!x}'!R. А в ЯП все-таки хочется получать какую-то дозу интуитивности. По крайней мере в Java/Kotlin/C что-то понятно на интуитивном уровне, а К, APL, Perl, даже F# я бы сказал — это отчасти write-only языки.
Для начала, try, if и when являются блоками, возвращающими значения (последняя строка в блоке)
То есть можно написать
fun muFunc(x: Int): Int = try {
  val y = ...
  x+y
}

и не мучиться с return?
Мне этот язык становится интересен.
К сожалению, Ваш пример не компилируется, не хватает catch:
fun myFunc(x: Int) = try {
    val y = 10
    x+y
} catch (e: Exception) {
    42
}

Зато можно не указывать, что возвращаете Int, компилятор и так об этом знает
Неприятно, что придется придумывать возвращаемое значение в невозможном случае. Но в catch ведь можно просто сказать throw e — тайпчекер это съест.
В этом случае Вам просто не нужен try. В Kotlin нет «checked» исключений.
Я return не хочу писать.
UFO just landed and posted this here
Если следовать канону пропадает смысл перехода со Scala.
Ещё можно вот так))
val myFun: (Int) -> Int = {
    val y = 10
    it+y
}

fun use() {
    myFun(10)
}

Но это будет работать только при одном входном параметре
То есть, несмотря на наличие локальной val, return писать не обязательно?
Дело не в локальной или не локальной val, а в том, лямбда это или нет. В данном случае поле — экземляр лямбды. Вот ещё вариант лямбды:
fun myFunc(x: Int) = {
    val y = 10
    x + y
}.invoke()

Это как run, только наоборот.
run, пожалуй, наиболее удобная конструкция. Придется писать на Kotlin — буду пользоваться.

В scala в этом месте return так же не нужен.

На расте так можно
fn add_2(x: i32) -> i32 { x + 2 }

Если вы используете параметры по умолчанию, и общее количество параметров достаточно большое, то лучше делать вызовы с именованными параметрами там, где метод/функция была использована. Тогда добавление новых параметров ничего не ломает.

Я, как-раз, пишу, что если выбирать не совсем корректное применение параметров по умолчанию, до добавление нового НЕ ЛОМАЕТ ничего, хотя по смыслу использования должно.
По поводу пункта 1.

1. Пожалуйста, убедитесь, что используете последнюю версию Kotlin Gradle Plugin и ‘kotlin-kapt’-плагина (https://kotlinlang.org/docs/reference/kapt.html);
2. Я добавил пример с QueryDsl в наш репозиторий с примерами (https://github.com/JetBrains/kotlin-examples/tree/master/gradle/kotlin-querydsl). Надеюсь, он поможет;
3. Не бойтесь публиковать ишью в наш баг-трекер (http://kotl.in/issue). Даже если то, с чем вы столкнулись, на самом деле не баг, мы постараемся вам помочь.
Ничуть не сомневаюсь. Но у меня maven, и переходить на gradle пока не собираюсь. В статье допишу вариант с переходом на gradle

Можете написать по какой причине? Предположу, что это "старый" проект, который продолжили писать на Kotlin.

Навскидку можно предположить больше причин:
1) Отсутствие нужных плагинов либо их недостаточно хорошая работа в Gradle. Как пример — при запуске JUnit тестов простым образом нельзя подсунуть Listener. Это аффектит работу Allure и либо требует некоторых и доработок, которые могут ломать привычные имеющиеся наработки.
2) Отсутствие специалистов. В любой технологии нужно разобраться. Если проект сложнее стандартного — доработать технологию под себя.
3) Боязнь Gradle из-за его некоторой нестабильности. Смена API для плагинов как пример(да, лично нарывался на ситуацию, когда это что то сильно аффектило). Другой пример — смена языка написания build-скриптов(Hello Kotlin!).
Потому что это было бы единственной причиной учить gradle. При этом использование QueryDsl у меня совершенно естественным образом перетекло в другой модуль (работа с фронтом отделена и только там мне понадобилось). Итог: проблемы бы получил, а выгоду — нет.
Проект не старый, изначально писался на Kotlin. Но достаточно старый чтобы застать проблемы с совместимостью с Spring.

По поводу пункта 5 — на мой взгляд, код получился достаточно понятным. А вот что в Котлине действительно выносит мозг, на мой взгляд, даже сильнее имплиситов в Scala, так это неявный this в лямбдах, через который делаются билдеры и прочие DSLи. Из-за него внутри лямбды магическим образом становится возможно вызывать методы, которые определены на типе receiver'а, и откуда эти методы берутся в конкретном куске кода, без дополнительного исследования понять нельзя. В Scala, например, через имплиситы нельзя добавить новые методы непосредственно в область видимости; новые методы могут быть добавлены только к какому-нибудь объекту (через имплиситные классы).


Понятно, что и в том и в другом случае при наличии IDE найти, откуда берется какой-то метод, не составляет особой сложности, но лично мое ИМХО — понять код с имплиситами в Скале проще, чем код с переопределенным this для лямбд в Котлине. Кроме того, синтаксическая привязанность неявно добавленных методов к объекту упрощает чтение — код в Котлине был бы существенно понятнее, хоть и существенно многословнее, если бы для вызова методов на this необходимо было бы всегда писать this явно.

Для укрощения неявных this в некоторых случаях может помочь аннотация @DslMarker.
Sign up to leave a comment.

Articles