Идёт мобильный разработчик по лесу, видит — Котлин горит. Сел в Котлин и сгорел

    Мир сходит с ума. Говорят, все новые мобильные проекты на Андроиде пишут исключительно на Котлине. В наше время очень опасно не учиться новым технологиям. Вначале твои знания устаревают, ты вылетаешь с работы, живешь у теплотрассы, дерёшься с бомжами за еду и умираешь в безвестности, так и не выучив функционального программирования. Поэтому я отправился на Курсеру изучать курс Kotlin for Java Developers и начал читать книжку (привет, abreslav, yole), поспрашивал друзей сами знаете откуда и вернулся назад с некой пустотой в душе. Помогите Олегу-путешественнику найти смысл в Котлине!


    • Бонус: хаброопрос «Как вы используете Kotlin?»



    ●  В Java ты чаще понимаешь по узкому контексту, что происходит. a = b — запись в поле или локал, a[1] = 2 — запись в массив. В Котлине за любым простым выражением может стоять сколь угодно сложный код из-за всяких умностей вроде перегрузки. Без IDE ничего не поймёшь. А IDE плохо, когда ты едешь в поезде и видишь, что свинговый жабоинтерфейс высасывает из ноутбука батарейку как вампир.


    ●  Котлин даёт одинаковый API для коллекций и сиквенсов, из-за чего люди злоупотребляют цепочками map/filter на коллекциях, создавая кучу промежуточных неленивых копий. Стримы в джаве специально введены для различия между ленивой и неленивой коллекцией. Да, есть инспекция в IDE для этого — потому что инспекции призваны исправлять недостатки языков.


    ●  Кстати, об IDE. Насколько хороша поддержка Kotlin в IntelliJ IDEA? Она действительно лучше, чем для Java? Есть большие сомнения. Может быть, кому-то из JB хватит духу проадвокатировать по данному вопросу.


    ●  Котлин форсит использование it, что приводит к нечитаемому коду. Что-нибудь типа seq.map { it -> foo(it, 1); }.map { it -> bar(it, 2); }.filter { it -> it.getBaz() > 0; }. Что это вообще было? Имена переменным даны не зря! А тут получается монолог вроде «Возьмём это, прикрутим к нему то, потом его закрутим и если оно стало больше того, то наденем сверху шарнир».



    ●  Цепочки вроде ?.let { foo(it); }?.let { bar(it); } — это вообще ад и должны быть запрещены в декларации о правах человека. И это считается идиоматично, Карл. В отличие от нормального if. Читать такой код невозможно.


    ●  От интеропа с джавой кровь идёт из глаз. А тут всякие JvmStatic и JvmName, и код превращается в цирк с конями.


    Например, вот у нас есть такое:


    class C {
        companion object {
            @JvmStatic fun foo() {}
            fun bar() {}
        }
    }

    Относительно помеченного аннотацией метода компилятор сгенерит и статический метод во внешнем по отношению к объекту классе, и метод экземпляра в самом объекте. Возможные варианты:


    • C.foo(); — работает
    • C.bar(); — синтаксическая ошибка, ибо метод не статический
    • C.Companion.foo(); — остается метод экземпляра
    • C.Companion.bar(); — единственный правильный способ

    Оправились от красоты решения? Окей, пошли дальше. Теперь вы готовы понять и принять тот факт, что, например, нельзя одновременно объявить два таких метода:


    fun List<String>.filterValid(): List<String>
    fun List<Int>.filterValid(): List<Int>

    Ведь их сигнатуры на уровне JVM совпадают: filterValid(Ljava/util/List;)Ljava/util/List;


    Поэтому нужно подпихнуть специальный костыль:


    fun List<String>.filterValid(): List<String>
    
    @JvmName("filterValidInt")
    fun List<Int>.filterValid(): List<Int>

    А как вам такое: в Kotlin нет checked exceptions. А в Java-реальности они есть. Отряд специального назначения «Боевые протезы» имеет честь представить новый самоходный костыль @Throws:


    @Throws(IOException::class)
    fun foo() {
        throw IOException()
    }

    Можно долго рассуждать, что «джависты постоянно ноют, что тут всё не как в джаве». Но если вот это красиво, то что тогда ужасно?


    В общем, рекомендуется открыть статью Java-to-Kotlin Interop и своими глазами посмотреть, как это выглядит.


    ●  Автоматические геттеры/сеттеры с добавлением английского слова get и первой буквой проперти в большом регистре (видимо, в локали ENGLISH? Ведь регистр букв системно-зависим) — это страшно.


    import java.util.Calendar
    fun calendarDemo() {
        val calendar = Calendar.getInstance()
        if (calendar.firstDayOfWeek == Calendar.SUNDAY) {  // call getFirstDayOfWeek()
            calendar.firstDayOfWeek = Calendar.MONDAY      // call setFirstDayOfWeek()
        }
        if (!calendar.isLenient) {                         // call isLenient()
            calendar.isLenient = true                      // call setLenient()
        }
    }

    ●  Экстеншн-методы загрязняют публичный интерфейс такими вещами, о которых автор и подумать боялся.


    Так как этой фичи нет в джаве, поясню. Можно написать любой метод, слева поставить имя «принимающего класса», и всё — он расширен. Давайте расширим MutableList функцией swap:


    fun MutableList<Int>.swap(index1: Int, index2: Int) {
        val tmp = this[index1] // 'this' относится к листу
        this[index1] = this[index2]
        this[index2] = tmp
    }
    
    val lst = mutableListOf(1, 2, 3)
    lst.swap(0, 2) // 'this' внтури 'swap()' будет иметь значение 'lst'

    Работа экстеншн-методов возможна, даже если автор специально сделал финальный класс, явно показав, что не хочет сторонних расширений. Получается что-то вроде изнасилования с особым цинизмом. И конечно, они ломают совместимость: что будет, если в следующей версии библиотеки автор добавит методы с теми же именами, но с другим возвращаемым типом? Он должен думать обо всех экстеншн-методах, которые любые люди могут добавить в тот же класс?


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


    ●  Библиотека местами не продумана. Например, reduce.


    Вот как выглядит reduce:


    listOf(1, 2, 3).reduce { sum, element -> sum + element } == 6

    Там есть только форма с identity (fold), но она не всегда применима.


    listOf(1, 2, 3).fold(0) { sum, element -> sum + element } == 6

    Кстати, почему Хабр подсвечивает эти две строчки по-разному? Аааа, уже неважно.


    По сути, fold и reduce делают одно и то же, но fold требует определённого начального значения, а reduce использует в качестве этого начального значения первый элемент списка. Соответственно, форма без identity кидает исключение для пустой коллекции.


    Всегда ли такое поведение всем нужно? Почему не вернуть какое-нибудь Optional и дать пользователю самому решить, что делать в случае пустой коллекции? Да или хоть null вернуть, раз уж это null-friendly язык.


    ●  Давайте ещё навалим про библиотеку. Нафига в стандартную библиотеку языка, который поддерживает дата-классы, включили пары? Это ж прямое поощрение плохого кода.


    Напоминаю, дата-классы выглядят так:


    data class User(val name: String, val age: Int)
    val duncan = User("Duncan MacLeod", 426) 
    val (name, age) = duncan
    println("$name, $age years of age") // печатает "JaDuncan MacLeodne, 426 years of age"

    Пара выглядит вот так:


    val (name, age) = Pair("Java", 23)
    println("$name, $age years of age") // тоже печатает "Java, 23 years of age"

    А все потому, что внутри:


    public data class Pair<out A, out B>(
        public val first: A,
        public val second: B
    )

    Совершенно очевидно, что среднестатистический быдлокодер забьёт писать свои классы на второй день использования, и код превратится в кошмарную пародию на лисп. Складываем огуречные жопки с сотнями нефти, пишем фильтры-франкенштейны и в продакшен. Быстро, просто, нечитаемо.


    ●  Очень странный момент — возможность не указывать возвращаемый тип метода (особенно публичного).


    Совсем недавно был случай в C++, от которого меня чуть не разорвало от злости. Программа падала в произвольном месте, а я не понимал — почему. Оказалось, в C++ можно не писать return в методе, который согласно сигнатуре должен что-то возвращать. Это не синтаксическая ошибка согласно стандарту, а undefined behavior. Соответсвенно, программа в рантайме падает с произвольной ошибкой. Чудесный язык — в нем есть специальный синтаксис для неработающих методов. С тех пор я очень аккуратно проверяю, что мы обещали вернуть из метода и что отдали на выходе. Эдакая параноидальная привычка.


    И вот теперь, в лучшем в мире языке Kotlin мы можем вообще не указывать возвращаемый тип. Это провоцирует людей писать нечленораздельную лапшу, в которой и ничего не понятно. Если метод a вызывает метод b, а тот метод c, а тот содержит в теле выражение when, в котором в ветках ещё три метода вызываются d, e и f, попробуй пойми тип метода а!


    fun a(check: Int) = b(check)
    fun b(check: Int) = c(check)
    
    fun c(check: Int) =
        when (check) {
            1 -> d()
            2 -> e()
            else -> f()
        }
    
    fun d() = "result 1";
    fun e() = "result 2";
    fun f() = "result 3";
    
    fun main(args: Array<String>) {
        println(::a.returnType)
        for (i in 1..3)  println(a(i).javaClass.name)

    Причём вначале вроде всё было просто и понятно, а в процессе эволюции поменялось, и капец. Меняешь возвращаемый тип метода f, и у тебя автоматом меняется возвращаемый тип метода а совсем в другом пакете, и ты не понимаешь, что происходит.


    Изначально в нашем примере выхлоп выглядел вот так:


    kotlin.String
    java.lang.String
    java.lang.String
    java.lang.String

    Но стоит только поменять определения функций на вот такие:


    fun d() = "1";
    fun e() = 100500;
    fun f() = listOf<String>();

    И результат тут же изменится на


    kotlin.Any
    java.lang.String
    java.lang.Integer
    kotlin.collections.EmptyList

    Никакой кристаллизации API. Для публичных методов явная спецификация API должна быть священной коровой, а Kotlin её не требует.


    Заключение


    Пожалуй, для начала достаточно. Из этой статьи может показаться, что все в Котлине плохо, но это очевидно, не так. Как минимум, зарплата Kotlin-разработчика обычно неплоха :-)


    В недавнем докладе на Joker 2018 (есть слайды), Паша (asm0dey) Финкельштейн отмечал, что на бэкенде Kotlin помогает писать более красивый и лаконичный код (но не всегда это получается), на нем получаются более выразительные тесты, с ним работает GraalVM, и всё это с примерами для Spring, Spring Security, Spring Transactions, jOOQ, и т.п.


    Стоит ли переходить на Kotlin с Java для мобильных приложений? Неясно. В любом случае, Kotlin интересный. Давайте в нём покопаемся!


    Минутка рекламы. Уже на этой неделе, 8-9 декабря 2018, пройдет конференция Mobius. На ней Святослав Щербина из JetBrains расскажет о том, как писать мобильные приложения на Kotlin Muplitplatform. Кроме того, можно будет пересечься со множеством людей, реально использующих Kotlin, и узнать, зачем и как они это делают. Места все еще есть, а вот времени уже почти не осталось, так что, если хотите прийти, сейчас у вас последний шанс. Билеты можно приобрести на официальном сайте.

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

    Как вы используете Kotlin?

    JUG.ru Group

    638,00

    Конференции для взрослых. Java, .NET, JS и др. 18+

    Поделиться публикацией
    Комментарии 319
      +11
      > Говорят, все новые мобильные проекты на Андроиде пишут исключительно на Котлине.
      Врут
        +19
        конечно, что не на Котлин, то на React Native.
          +7
          React Native — легаси и прошлый век. Flutter
            +13
            Как быстро во фронтенде летит время.
            Один час на Земле равен 30 годам во фронтенде…
              0
              Да ладно, флаттер нормальная технология. Самое главное что к js, html и css отношения не имеет.
              +3
              Вы в слове «говно» 7 ошибок сделали
          +3
          Олег забыл написать, что на Мобиус будет выступать Святослав Щербина из JetBrains с рассказом о том, как писать мобильные приложения на Kotlin Muplitplatform.
            +3
            Поправил!
            +4
            и тернарного оператора нет!
              +4
              А нафига вам тернарный оператор, если if — это expression?
                +3

                потому что if требует скобок, больше текста, имхо он менее четаем

                  +2

                  Если не надо вычислять первое значение, то можно коротко так:


                  var t = Value0.takeIf(expression) ?: Value1

                  костыль, но чем-то похож на тернарный...

                    +6
                    Это одна из причин, по которым автору статьи и не нравится Котлин — чрезмерное использование «идеоматических» конструкций. В данной ситуации if будет более разумным выбором, на мой взгляд.
                      +1
                      Я бы даже сказал по-другому: «чрезмерное использование конструкций „костыль, но чем-то похож на...“)))
                +5
                тернарный оператор в Kotlin записывается вот так

                val max = if (a > b) a else b


                это возможно потому, что блоки внутри if возвращают значение
                +36
                seq.map { it -> foo(it, 1); }.map { it -> bar(it, 2); }.filter { it -> it.getBaz() > 0; }

                И что вам мешает писать понятнее? Во первых it неявен, и его указывать не надо, во вторых в вашем же примере напишите.
                seq.map { s -> foo(s, 1); }.map { f -> bar(f, 2); }.filter { b -> b.getBaz() > 0; }

                или если уж c it
                
                seq.map { foo(it, 1); }
                     .map { bar(it, 2); }
                    .filter { it.getBaz() > 0; }

                Все остальные жалобы так же на то, что в котлине можно писать нечитаемый код. Называйте переменные нормально.

                даже если автор специально сделал финальный класс, явно показав, что не хочет сторонних расширений.

                Экстеншен методы — это синтаксический сахар. У них не динамическая диспетчеризация.

                видимо, в локали ENGLISH? Ведь регистр букв системно-зависим

                Ага. Прямо как в JavaBeans naming convention. Смотрите метод java.beans.Introspector.decapitalize

                Тут можно много о чем спорить, но большинство ваших негодований выглядят притянутыми за уши либо звучат как «смотрите какой быдлокод я могу написать, а язык не мешает».
                  +15
                  Тут можно много о чем спорить, но большинство ваших негодований выглядят притянутыми за уши либо звучат как «смотрите какой быдлокод я могу написать, а язык не мешает».
                  Проблема в том, что в этом — сама суть Java: язык, в котором на разработчика надевают смирительную рубашку, так что даже человек без опыта, изучивший Java на двухнедельных курсах может что-то писать по данному ему техзаданию.

                  Kotlin в эту нишу не вписывается от слова «совсем»… с чем разработчикам, долго работавшим на Java, тяжело смириться.

                  P.S. Собственно если вы посмотрите на историю развития Java — то это постоянная борьба между людьми, которые хотят новые фичи, так как это позволяет писать более читабельный код — и людьми, которые пытаются их не допустить, потому что они также позволяют читать менее читабельный код…
                    +10
                    так что даже человек без опыта, изучивший Java на двухнедельных курсах может что-то писать по данному ему техзаданию.

                    Да ладно вам. Смочь то он сможет, но это не отменяет того факта, что он будет писать кривой код. Ну и непонятно, что помешает ему называть переменные непонятно, что будет мешать ему заводить кучу анонимных классов и т.д.
                    Ну вот правда. Рассказывать о том, что на джаве тяжело новичку написать лапшекод — это даже не смешно.

                    Тут ведь большая часть проблем — совсем не проблемы. fold и reduce работают так везде, странно было бы ожидать другого поведения. Капитализация — как в джаве.

                    Исключения — да, не как в джаве. Но в jvm во первых проверяемых исключений нет, а во вторых — и в джаве уже вроде как признали, что они были ошибкой. UncheckedIOException не от хорошей жизни появился.

                    Претензиии к интероперабельности — тоже не в кассу.

                    В итоге то что от критики осталось? Я вижу только «все не как в джаве» и «методы работают как во всех языках, но мне непонятно».
                      –2
                      > в джаве уже вроде как признали, что они были ошибкой

                      Кто эти люди, которые признали? Рейнхольд? Роуз? Гёц? Мне checked exceptions как раз кажутся очень крутой фичей, всегда их юзал.
                        +13
                        В предыдущем разговоре с вами мы как-то уже выясняли, что мир не вращается вокруг вашего опыта.

                        Сhecked exceptions во первых бесполезны кроме как для информативной точки зрения. Логика обработки эксепшенов в вашем коде обычно никак не должна зависеть от того, объявлен ли в методе throws, поскольку у нас есть такая вещь как RuntimeException, который может внезапно прилететь из сторонней либы. И хорошо написанный код обязан подобные вещи учитывать. А может оттуда и checked exception прилететь легко. Даже без объявления. Потому что это фича языка, а не платформы.
                        А во вторых, они слабо совместимы с функциональным стилем программирования.
                          +4
                          А во вторых, они слабо совместимы с функциональным стилем программирования.

                          Почему? В ФП ML-ского толку я очень люблю возвращать ошибки через Either ErrorsADT ResultType, что очевидно изоморфно ResultType Function(...) throws(ErrorsADT). Очень хорошо и типобезопасно получается.


                          Другие поинты я тоже могу обсудить с позиции ФП и типобезопасности (в частности, например, почему RuntimeException не нужно обрабатывать так же), но только если вы захотите — я не настолько знаю джава-экосистему, чтобы вот так сходу на неё натягивать свой опыт.

                            +4
                            я очень люблю возвращать ошибки через Either

                            Ну не через эксепшены же.
                            Потому что в джаве, при ее наличии требований к checked exceptions код лямбд зачастую превращается из
                            .map(s -> foo(s))

                            в
                            .map(s -> try {
                               return  foo(s)
                            } catch(Exception e){
                              throw new RuntimeException(e)
                            })


                            И да, в джаве нет монады Try. И не будет. Я задавал этот вопрос Хорстманну на какой-то конфе, в ответ получил вопрос что это «not in spirit of java»
                              +2

                              Смотря какие ошибки. Если у меня нарушены инварианты, которые здесь нарушены не должны быть вообще никак (и которые, например, в языке с более мощной системой типов я мог бы выразить в этих самых типах, или же мог бы поймать, если бы несколько дней потратил на ручку с бумажкой, дабы проанализировать алгоритм), то я не сильно парюсь и пишу error $ "funcName: " <> show arg <> " is invalid" или вроде того.


                              Собственно, такой экзепшон в чистом коде (сиречь в какой-то бизнес-логике) вы поймать потом всё равно не сможете, придётся ловить его где-то на очень высоком уровне, где вы сможете, например, перезапустить нужное вычисление с другими параметрами, отправить емейл/смску себе, создать таск в джире с приводящими к нарушению инвариантов параметрами, или что-то такое.

                              +3

                              Проблема checked exceptions в том, что в конструкции throws нельзя использовать типы-параметры.


                              Как следствие, если тип Either ErrorsADT еще можно выразить на Java, то тип Either в рамках вашего изоморфизма уже невыразим.


                              Собственно, на этом все ФП и заканчивается.

                                +3

                                Хм.


                                То есть, я не могу написать функцию, которая бы принимала две функции с произвольными throws-аннотациями, вызывала бы их обе внутри себя и имела бы throws-аннотацию из их объединения?

                                  +2
                                  Да, и это тоже не можете.
                                    +3
                                    А, ну тогда по совокупности понятно, почему к checked exceptions негативно относятся. Плохо зделоли, в общем.
                                      +1
                                      Так всё упирается в то, что давно и очень быстро делали. Дженериков-то там, на самом деле, нету.

                                      Всё что есть — сделано через динамическую типизацию и обмазку в компайл-тайм.
                                        +1
                                        через динамическую типизацию

                                        Не совсем. Просто компилятор при получении из метода T get() проставляет приведения Integer i = (Integer)get(); к заранее известным типам. Дальше доступ к полям и методам идёт как обычно. Поиска по имени метода при каждом вызове, к счастью, нет.

                                          +1
                                          Проблема в том, что рантайме никакого T get() нету. Есть вовсе даже Object get(). И он, вообще говоря, может вернуть что угодно. Динамическая типизация в чистом виде.

                                          А приведение типов и выброс исключения — это как раз та «обвязка», о которой я говорил.

                                          Это неплохо работает, на самом деле, TypeScript устроен почти так же. Просто нужно не забывать об ограниченности такого подхода.
                                            +1

                                            Статическая и динамическая типизация — это фичи языка, а не рантайма. И вернуть что угодно он не может: компилятор гарантирует*, что этот каст всегда будет успешным (при соблюдении некоторых правил).


                                            * на самом деле нет. Чертовы массивы все портят. Вот за каким надом их решили сделать ковариантными?

                                              +1
                                              Не гарантирует компилятор нифига. Раздельная компиляция потому что. И ничто вам не мешает изменить код так, чтобы все ваши инварианты порушились.
                                                +1
                                                Ну, если компилировать с одной версией библиотеки, а использовать потом другую — то да, так и будет. Но зачем так делать-то?
                                                  +1
                                                  Там есть соседняя тема, где всё это уже обсудили в очередной раз, с самыми последними аргументациями.
                                                  +2

                                                  То, что язык позволяет загружать динамические библиотеки, не делает его языком с динамической типизацией. Это динамическая компоновка.
                                                  По аналогии, даже в С/С++ можно подсунуть неправильную dll (но в нормальных сборках всё-таки используют корректные dll, а не какие попало), но язык динамическим от этого не станет. Подозреваю, что даже в хаскеле так можно.

                                    +3
                                    Проблема checked exceptions в том, что в конструкции throws нельзя использовать типы-параметры.

                                    Вполне можно. Вот такой код прекрасно скомпилируется, по крайней мере в Java 8:
                                    public void <E extends Exception> void func() throws E {
                                    }
                                      0

                                      Хм, почему-то я об этом не знал… И ведь даже вывод типов работает! В таком случае еще не все потеряно.

                                        +1
                                        Нужно только понимать, что это, в действительности, просто отмена checked exceptions.

                                        В рантайме-то там никакого E не будет, будет просто throws Exception (плюс, возможно, автозаворачивание checked exceptions в unchecked).
                                          +2

                                          А какая разница что там в рантайме? Компилятор же гарантирует, что "левым" исключениям просто неоткуда взяться.

                                            +1
                                            Компилятор не может ничего гарантировать про код, которого он не видит.

                                            А .jar, с которым вы собираете ваш проект вовсе не обязан совпадать с тем, что будет реально задеплоено.
                                              +1
                                              Но зачем так делать?
                                                +1
                                                Что значит зачем? Это делается постоянно, и это вполне нормальное поведение

                                                Затем, что это внезапно стандартное поведение для j2ee библиотек. См. Dependency Scope = provided, и зачем он нужен.

                                                Или затем, что ваша библиотека может зависеть от super-mega-lib версии 42 и собираться с ней, а тот кто вашу либу подключает — от версии 43. И в рантайме вы будете иметь в класспасе именно 43 версию. Или он может зависеть от другой либы, которая использует новую версию super-mega-lib

                                                Это во первых. А во вторых — компилятор ничего не гарантирует, как сказали.
                                                  0
                                                  > Затем, что это внезапно стандартное поведение для j2ee библиотек.

                                                  j2ee — это та технология, от которой в конце концов отказался Oracle, выпилил все её следы из OpenJDK (включая даже такие повсеместные мелочи как java.bind.xml) и отдал на спасение в Eclipse Foundation? =)

                                                  отличный пример, чудесный
                                                    +1
                                                    Да, замечательный пример. Обратите внимание, один из — просто как пример, где часто используются provided зависимости. Живее всех живых. Сервера приложений и контейнеры от этого никуда не делись.

                                                    Я вообще уже рекомендовал вам расширять кругозор, не все в мире джавы крутится вокруг того что делает оракл, и не все приложения на бакенде — это уберджары на спрингбуте. Даже если вы лично больше ничего никогда не видели.
                                                      0
                                                      Ну как никуда не делись, j2ee уже всё — теперь осталась некая надежда на джакарту, и там основной сэллинг поинт это как раз cloud native из коробки, если это выстрелит — то наследие j2ee будет жить

                                                      А про спрингбут… Да я видел много всего, но по ходу пришел к выводу, что уберджары на спрингбуте — это самое крутое и удобное :)

                                                      И этот подход даже не про джаву, а вообще, про жизнь. Например, я использую GNU/Linux и вижу, насколько круче юзабилити у докерных контейнеров или «все свое тащу с собой» по сравнению с пакетным менеджером. Сейчас у меня есть несколько сайтов про разные вещи, и я везде перешёл к хранению важного софта в self-contained докерах, включая базу данных. Это не просто какой-то непонятно откуда взявшееся утверждение, а моё личное глубокое убеждение о том, как должно выглядеть правильное решение, как я делаю и буду делать у себя.

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

                                                        И это не самое удобное. Это вам так кажется, не знаю почему. Возможно от недостатка опыта. Возможно потому что вы не рассматриваете ничего за пределами REST-бакенда

                                                        В гриде например, в каком-нибудь MR-решении, или в том же апач шторме ваш спрингбут не заработает. Или когда у вас приложение работает с несколькими базами и там сложные бизнес-правила по транзакциям — замучаетесь со спрингбутом. Короче все что выходит за рамки «написать crud приложение». У меня опыт, что спрингбут дает больше проблем, чем решает, как только ситуация становится чуть-чуть нестандартной,.

                                                        И вдвойне непонятно, как этот тезис относится к моему предыдущему комментарию. Я писал про то, как в рантайме может возникнуть ситуация, когда jar отличается от того, что был при компиляции.

                                                        если я использую какую-то технологию, то жду, что технология поддерживает это убеждение. Если нет, она просто не подходит, надо брать другую.

                                                        Очень хорошая позиция. «Если технология и факты противоречат моему манямирку, то это плохая, негодная технология, зделоли плохо». Я теперь понимаю, откуда все тезисы в этой статье.
                                                          +1
                                                          Если вы собрали всё вместе сами и всё своё тащите с собой (то есть, не используете всякие адовые аппликейшен серверы), то вы полностью контролируете, что за джарки используются. Closed world почти что — всё известно на этапе компиляции. Всё что после этого интересно от среды выполнения — конкретный билд OpenJDK, версия glibc и возможно, ядра Linux. (При этом есть возможность отвязаться и от версии OpenJDK, скомпилировав всё в self-contained exe file, но для этого нужен либо GraalVM, либо Excelsior JET). Очень элегантно. Да, продвигаю это везде — мне нравится, вот и продвигаю. Например, в Golang это поведение по умолчанию.
                                              +1

                                              Компилятор казалось бы гарантирует, но на самом деле для того, чтобы "левые" исключения спокойно появились где угодно достаточно подключить Lombok

                                              +2
                                              Никакого заворачивания точно не будет, потому что в рантайме никаких checked exception нет.
                                              По этой же причине не будет и throws Exception — для JVM просто нет такого понятия, все проверки check exceptions совершает компилятор.
                                        +1
                                        Тут хорошо расписано.
                                          +1
                                          По вашей ссылке нет ничего что бы относилось к ФП. Иммутабельные данные не могут оказаться в «corrupt state» по построению.
                                            +1
                                            Так мы вроде джаву обсуждаем, а не ФП. Про ФП всколь сказано в контексте «А вот в ML», но мы вроде JVM и все к нему относящееся смотрим.

                                            Плюс, эксепшны в любом случае плохо работают с многопотоком. В распространенных языках вставляют всякие известные костыли вроде

                                            To make it easier for developers to write asynchronous code based on Tasks, .NET 4.5 changes the default exception behavior for unobserved exceptions. While unobserved exceptions will still cause the UnobservedTaskException event to be raised (not doing so would be a breaking change), the process will not crash by default. Rather, the exception will end up getting eaten after the event is raised, regardless of whether an event handler observes the exception.
                                              +1

                                              Мы обсуждаем вот это:


                                              А во вторых, они слабо совместимы с функциональным стилем программирования.
                                                0

                                                Ну вот hidden state кмк с ФП плохо сочетается. ФП поощряет использование типов, и информация об ошибках должна быть в них описана. А получается, что написано, что функция возвращает T, а на самом деле оказывается, что Either<T, Either<Err1,Err2,Err3>>

                                    0
                                    Рассказывать о том, что на джаве тяжело новичку написать лапшекод — это даже не смешно.
                                    Лапшекод, написанный на Java, те не менее, будет работать и его можно будет понять. А вот в JavaScript можно такого понаписать, что в коде вообще ничего ни понять, ни исправить будет нельзя… Kotlin находится где-то посередине…
                                      +4
                                      Лапшекод, написанный на Java, те не менее, будет работать и его можно будет понять

                                      Тут я согласен. Вернее как. Его скорее всего будет проще понять — так точнее наверное. Хотя в связи с последними нововведениями в джаве то уже может быть затруднительно.

                                      Я могу сказать из своего круга окружения — хорошие разработчики попробовав котлин в своей массе на джаву возвращаться не хотят. Для меня это все таки больший показатель качества языка.
                                        +8
                                        Про это я ещё раньше написал. Бегать в смирительной рубашке с завязанными на спине рукавами — тяжело. Но как только вы их отпускаете — «недоучки с двумя месяцами курсов» начинают порождать чёрт-знает-что.

                                        И между этими двумя проблемами развитие Java и прыгает… Kotlin же с самого начала сказал: «да, применяя эти фичи бездумно можно написать непонятный код… и это — не наша проблема», что, собственно, и привело автора статьи в уныние…
                                          +1
                                          Вторая проблема в какой-то мере решается введением ревью, кодстайлов и прочих линтов. Понятно что не идеально, но все таки.
                                          Первая проблема не решается. Да, как вы и писали.
                                          –1
                                          А хороший ли разработчик определяются тем, хотят ли они возвращаться с Котлина на Жава или нет?
                                      +11
                                      Проблема в том, что в этом — сама суть Java: язык, в котором на разработчика надевают смирительную рубашку

                                      Да ладно, ничто этому человеку не помешает написать хренову кучу фабрик, адаптеров, визиторов и прочих абстракций на ровном месте. И читать эту писанину потом также тяжело.
                                        +4
                                        Есть ощущение, что это дело привычки. У нас был один пришелец из мира Java — он этих «абстракций» на C++ тоже наплодил столько, что мы их уже третий год изничтожаем.

                                        А ему — нормально, когда один класс без методов расширяет другой класс, тоже без методов, который расширяет ещё один (тоже, разумеется без методов).
                                          0

                                          Может это как-то связано с Open/Closed Principle из SOLID? На новую функциональность нужно пилить новый класс, старый класс менять нельзя. В Java понятно, что сам факт создания класса есть новая функциональность, ибо описание класса доступно через рефлекшен. Может, там где-то RTTI, или даже полноценный RTTR?

                                            +1
                                            Там было три уровня наследования классов. И у них была куча вспомогательных классов.

                                            Самое весёлое — что всё это было нужно для поддержки разных платформ и вполне можно было бы обойтись буквально парочкой ifdef'ов и некоторым количеством шаблонов.

                                            Но в Java нет ifdef'ов и шаблонов, а для их замены есть… вот это.
                                              +1

                                              В котлине кстати для мультиплатформенной сборки можно использовать expected(объявление без реализации) методы и классы. Некий аналог header файлов из cpp.

                                            +1
                                            Есть ощущение, что это дело привычки.

                                            Есть ощущение, что это от переизбытка умных книжек и бездумного им следования.
                                      +6

                                      Претензия к reduce/fold непонятна и выглядит надуманной. Javascript, Haskell, C# — никто не возвращает Optional! Это же попросту неудобно в большинстве случаев!

                                        +2

                                        Нуу, foldl1 на пустом списке там кидает экзепшон, например, а аналогичный примитив из линзочек вообще решает этот вопрос требованием свёртки только по моноидам, возвращая единицу, если там пусто. Не могу однозначно сказать, удобно это или нет. Помогает писать безопасный код, в принципе.

                                          +2

                                          Так и я про то же самое говорю. В Котлине все так же, только моноидов нет.

                                        +8
                                        Цепочки вроде ?.let { foo(it); }?.let { bar(it); } — это вообще ад и должны быть запрещены в декларации о правах человека. И это считается идиоматично, Карл. В отличие от нормального if. Читать такой код невозможно.
                                        Знаете, «идеоматично» и «рекомендовано» — это как бы сильно не одно и то же.
                                        На примере JS, посмотрите, какой код компилирует Babel или тот-же Kotlin. Он на 100% идеоматичен, но за написание такого кода руками в приличном обществе принято очень больно бить ногами и эти самые руки отрывать.
                                        Очень странный момент — возможность не указывать возвращаемый тип метода
                                        Во-первых, вам никто не запрещает его указывать, это как минимум правило хорошего тона, даже в языках с динамической типизацией.
                                        Во-вторых, если мне память не изменяет, в Котлине тип dynamic поддерживается только для JS, а для jvm — это вывод типов на этапе компиляции. То есть геморрой с отладкой будет, но скомпилироваться в нерабочий код оно не сможет.
                                        Совершенно очевидно, что среднестатистический быдлокодер забьёт писать свои классы на второй день использования, и код превратится в кошмарную пародию на лисп.
                                        Хорошая предъява к языку.
                                          +5
                                          Это разумная предъява.
                                          Когда-то из языков изгоняли GOTO, чтобы не было ВОЗМОЖНОСТИ писать путанный код.
                                          Язык не только не должен провоцировать писать плохо, он должен провоцировать писать ясно.
                                            +5
                                            Я подозреваю, что Pair существует, чтобы можно было писать `mapOf(key1 to value1, key2 to value2)` и подобное. Инфиксная функция `to` как раз и создает пару.
                                              +1

                                              не обязательно для mapOf:


                                              typealias MyPair= Pair<Int, String>
                                              
                                              infix fun Int.to2(that: String): MyPair = MyPair(this, that)
                                              
                                              fun main() {
                                                val m = mapOf(1 to2 "we")
                                                val l = 2 to2 "test"
                                              }

                                              это удобнее, чем городить data-класс из двух полей и не зависит от конкретной реализации Map.
                                              А ещё это позволяет "городить" именованный перебор key-value коллекций


                                              PS: и да, olegchir забыл упомянуть, что есть не только Pair, но и Triple...

                                          +8
                                          От интеропа с джавой кровь идёт из глаз. А тут всякие JvmStatic и JvmName, и код превращается в цирк с конями.

                                          Согласен, но мое личное мнение — не надо писать на котлине для джавы. Нужно писать на котлине для котлина. Тогда и проблем с интеропом не будет


                                          Давайте ещё навалим про библиотеку. Нафига в стандартную библиотеку языка, который поддерживает дата-классы, включили пары? Это ж прямое поощрение плохого кода.
                                          Совершенно очевидно, что среднестатистический быдлокодер забьёт писать свои классы на второй день использования, и код превратится в кошмарную пародию на лисп

                                          В некоторых ситуациях Pair вполне себе подходит (когда нужно передать пару значений буквально на одной промежуточной операции). Не городить же отдельный бессмысленный дата-класс под каждый такой случай. А что до быдлокодеров — если вы насильно уберет у них Pair это не означает что они сразу станут писать хорошо (или не сделают этот Pair себе сами)


                                          Не стоит забывать, что возможность сделать что-то, не означает необходимость делать это.


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

                                            +6

                                            Непривычно и неудобно по сравнению с Java — только если ничего, кроме Java, в глаза не видеть.

                                              +8
                                              «неудобно по сравнению с Java» вообще больше похоже на оксюморон, как по мне
                                            +4
                                            В Java ты чаще понимаешь по узкому контексту, что происходит. a = b — запись в поле или локал, a[1] = 2 — запись в массив ..

                                            Да, частично это так. Но с помощью такой записи можно существенно упростить код:
                                            Как самый простой пример:
                                            HashMap<String, Map<String, String>> someMap = new HashMap<>();
                                            //Java
                                            someMap.put("key","value");
                                            //Kotlin
                                            someMap["key"] = "value"

                                            Котлин даёт одинаковый API для коллекций и сиквенсов, из-за чего люди злоупотребляют цепочками map/filter на коллекциях, создавая кучу промежуточных неленивых копий

                                            Возможно только по незнанию и на первых порах. Одинаковый api позволяет делать многие сложные преобразования гораздо проще. И чтобы не плодить промежуточные цепочки (хотя иногда и они нужны) достаточно просто перейти к sequence.
                                            Кстати, об IDE. Насколько хороша поддержка Kotlin в IntelliJ IDEA? Она действительно лучше, чем для Java?

                                            Да, она хуже :) но не сильно. Если даже сравнивать с тем же Go, то поддержка языка лучше сделана. (да и сам релиз Kotlin состоялся только в 2016, пара лет всего прошло)
                                            Котлин форсит использование it, что приводит к нечитаемому коду. Что-нибудь типа seq.map { it -> foo(it, 1); }.map { it -> bar(it, 2); }.filter { it -> it.getBaz() > 0; }. Что это вообще было?

                                            Это может вызывать трудности только по началу. It значительно упрощает написание лямбд с одним аргументом. А в тех местах, где есть сложные преобразования всегда можно перейти к именованному аргументу.
                                            Цепочки вроде ?.let { foo(it); }?.let { bar(it); }

                                            Аналогично, сложности только по началу возникают. И Если таких цепочек становится много, то скорее всего что-то делается не так, и скорее всего можно сделать по другому.
                                            От интеропа с джавой кровь идёт из глаз

                                            Отчасти согласен, что местами не очень удобно, но все довольно просто и понятно. Даже тот же @JvmStatic по больше части не нужен, и функция просто выносится на уровень файла.
                                            Экстеншн-методы загрязняют публичный интерфейс такими вещами, о которых автор и подумать боялся.

                                            Автору и не нужно думать :)
                                            Это лишь способ сделать api удобнее у классов, которые чаще всего используются в проекте. И в любом случае от них гораздо больше пользы чем вреда.
                                            Библиотека местами не продумана. Например, reduce.

                                            Тот пример с reduce/fold, что вы привели, это довольно устоявшаяся конструкция. И как уже было сказано выше, текущая реализация вполне удобна.
                                            Давайте ещё навалим про библиотеку. Нафига в стандартную библиотеку языка, который поддерживает дата-классы, включили пары? Это ж прямое поощрение плохого кода.

                                            Как же без пар :) Они весьма полезны. И в коде очень часто возникает необходимость вернуть именно два аргумента, и для этого отлично подходит пара. Да, не везде их нужно использовать, и порой лучше сделать еще один «data class», но для «write once» или просто прототипирования они подходят отлично. А говнокод можно сделать и без них.
                                            Очень странный момент — возможность не указывать возвращаемый тип метода (особенно публичного).

                                            Иногда его и правда можно опустить. Как возвращение того же when, или простые однострочные конструкции. Но по большей части хорошей практикой считается явное указание возвращаемого типа.
                                              +1
                                              так и не выучив функционального программирования

                                              Не совсем понятно причем здесь ФП

                                                +4

                                                Прочитал первый абзац и заключение и понял что автор толком ни в чем не разобрался и наверное не особо хочет разбираться.


                                                Без IDE ничего не поймёшь. А IDE плохо, когда ты едешь в поезде и видишь, что свинговый жабоинтерфейс высасывает из ноутбука батарейку как вампир.

                                                Ситуация высосана из пальца. Не соглашусь в корне, в Java тоже есть много всякого во что без IDE сложно въехать. Перегрузку операторов вас никто не заставляет использовать, на Котлине можно писать в Java 6 стиле если очень хочется, дятловать или нет вам решать.

                                                  +2
                                                  > и наверное не особо хочет разбираться

                                                  не просто хочу разбираться, а в некотором смысле это теперь моя работа.
                                                    +5

                                                    Не совсем понимаю, в чем проблема "Без IDE ничего не поймешь".


                                                    Иногда выбор языка основан на степени "ВАУ, СКОЛЬКО ВСЕГО В IDE ДЕЛАЕТСЯ ЗА МЕНЯ!".
                                                    Отбрасывать инструмент, с которым проводишь рабочее/личное время потому, что когда-то, возможно, в каком-то поезде, где почему-то нет возможности зарядиться, (но есть необходимость работать) ноутбук сядет на пару часов быстрее — как-то… необычно.

                                                      +1
                                                      Каждый проект на Github надо открывать в IDE, чтобы прочитать, что там происходит?
                                                        +1
                                                        Большой и на джаве (особенно на современной, куда вот подвезли стримы и автоматический вывод типов локальных переменных) — да, однозначно. Ну, по крайней мере, в той же мере, в какой и на Kotlin.
                                                          +2
                                                          Перегрузка операторов, она же не для того, чтобы вам навредить, сделана. Если написано a + b, значит это сложение. Вот и всё. А в детали зачем вам вдаваться? Вы код просматриваете, общую логику пытаетесь понять. В гугле там нашли алгоритм и читаете. Если надо вдаваться в детали, ну можно и влезть, и IDE не обязательно, хотя с ней и проще. Серьёзный анализ кода через просмотр кода в браузере звучит немного странно, хотя, наверное, с умным сервером и такое возможно, просто никто не сделал. А для поверхностного предполагается, что перегрузка операторов используется к месту. К сожалению всегда найдутся уникумы, которые перегрузят какой-нибудь битовый сдвиг для ввода-вывода, но вроде сейчас уже все понимают опасность такого подхода и обычно не злоупотребляют. Я, лично, за несколько лет перегрузил оператор только один раз, это был оператор деления и я его использовал как разделитель каталогов, да и то сомневаюсь в уместности, хотя читается, на мой взгляд, понятно.
                                                            0
                                                            Да даже если вдаваться.
                                                            Я вот лично не понимаю, почему a+b нельзя читать в браузере без IDE потому что непонятно что там происходит внутри оператора сложения, а выражение a.plus(b) — легко, удобно и понятно.
                                                      +2
                                                      Совершенно очевидно, что среднестатистический быдлокодер забьёт писать свои классы на второй день использования, и код превратится в кошмарную пародию на лисп.

                                                      Я писал AWS Lambda на Котлине в ФП стиле с карированием, композицией функций и использованием исключительно функций. Так вот если вы вменяемы и пишите тесты до или после ваших функций, то ваш код выглядит не хуже а даже лучше привычного SOLID-ного кода, ибо тут не один класс, одна ответственность, а одна функция.


                                                      Не вижу смысла использовать классы как средство защиты от быдлокодеров, это как минимум предвзято. Шедевры такого рода на несколько порядков чаше встречаются, как раз, в мире ООП откуда и родились анти-паттерны типа God Object итд.

                                                        +2

                                                        Мне очень понравились комментарии:


                                                        • в Котлине есть вот такая вот неоднозначная фича
                                                        • ну так никто не заставляет Вас её использовать.

                                                        Интересно зачем вводить фичи в язык, которые не нужно/не надо использовать? Был тут один такой язык С++ называется.


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

                                                          +4

                                                          Вы невнимательно читали комментарии, правильная цитата должна выглядеть вот так:


                                                          ну так никто не заставляет Вас её так использовать.

                                                          Вот есть в языке фича — давать переменным произвольные имена. Хорошая она или плохая? Я считаю что хорошая — я могу дать переменным осмысленные имена, и код станет понятнее. Но кто-то другой даст всем переменным имена a1, a2 и a3 — и код будет непонятным. Становится ли фича "давать переменным произвольные имена" от этого неоднозначной?

                                                            +1

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

                                                              +1
                                                              Ну скажем так… наверное, полезно иметь больше чем одну точку зрения. Чтобы когда условия поменяются, не бегать с горящей задницей кругами :) Точка зрения в посте выбрана очевидно какая, да. Я мог бы написать и с какой-нибудь другой точки зрения, но это неинтересно — обожающих постов, вылизывающих Котлин теплыми щенячьими языками — весь интернет ими переполнен, а толку?
                                                                +3

                                                                А что не так со стабильностью и долговременной поддержкой? И какое отношение к ней имеют выдуманные претензии из обсуждаемого поста?


                                                                Вот три пункта из комментария ниже от Dveim — и те выглядят куда серьезнее...

                                                                  0

                                                                  Что не так с совершенно обоснованными претензиями из обсуждаемого поста? Всё с ними так. У вас есть пример какого нить долговременного проекта с похожим синтаксисом?

                                                                    +1
                                                                    Вы заходите на второй круг. «Совершенно обоснованные» претензии уже разобрали в других комментариях.

                                                                    Про долговременные проекты на Kotlin ничего не знаю, поскольку пишу на другом языке. Но половина «ужаснейших» с точки зрения автора поста фич давным-давно есть в C#, на котором написан тот же Stack Overflow. C 2008 года и по наше время — это достаточно долгоживущий проект?
                                                                      0
                                                                      Ну строго говоря, про C# — это не совсем валидный аргумент. Язык — это больше, чем просто набор фич. Недостаточно просто собрать в кучу все что знаешь, и назвать это языком, с таким подходом это будет скорей помойка :) C# — это целостная система ценностей и трейдоффов, другая система.
                                                                        +1
                                                                        несколько лет назад сбежал из C# разработки в PHP, тогда еще такого ужаса не было, если сейчас оно там все так, то я рад что сделал это еще тогда.
                                                                          +1
                                                                          Сколько лет назад? Большая часть претензий автора актуальна для c# 3.0 который 10 лет назад релизнулся…
                                                                        0
                                                                        Разумеется. В соответствии с вашими описаниями Kotlin — это п$здец, а C++ — это п$здец² (или даже п$здец³). Тем не менее на C++ имеется куча долговременно поддерживаемых проектов. Гораздо, гораздо больше, чем, скажем, на языке Ада — хотя тот, как бы, специально создавался для «стабильности и долговременной поддержки».

                                                                        Черезмерное увлечение «стабильностью и долговременной поддержкой» приводит к тому, что хорошие разработчики начинают язык избегать (из-за многословности и невозможности писать код кратко и понятно)… и вот это влияет на проекты, в долгосрочной перспективе, куда сильнее, чем возможность писать быдлокод.
                                                                          0

                                                                          Не знаю как Вы посчитали это влияние. Наверное на листочке где-то. Или влияметром.


                                                                          Пример крупных проектов на C++ не засчитывается:
                                                                          1) Он появился давно и альтернатив было немного
                                                                          2) За 20+ лет появились вот такие вот монстры на основе пота и крови сотни разработчиков

                                                                            +2
                                                                            1) Он появился давно и альтернатив было немного
                                                                            Вообще-то тогда (как и сейчас) количество языков исчислялось сотнями. Так что про «отсутствие альтернатив» — не стоит. Вспомните хотя бы Pascal, на котором первые продукты, написанные не на ассемблере, и Apple и Microsoft писали.

                                                                            2) За 20+ лет появились вот такие вот монстры на основе пота и крови сотни разработчиков
                                                                            У старых Java проектов — тоже Style Guide'ов хватает, так что мимо.
                                                                  +3
                                                                  Мне очень понравились комментарии:

                                                                  в Котлине есть вот такая вот неоднозначная фича
                                                                  ну так никто не заставляет Вас её использовать.

                                                                  Секундочку, Котлин язык прагматичный, построенный, между прочим, на опыте использования Java (зачастую на неоправданных ожиданиях), следовательно язык включает в себя некоторые плюшки и даже дуализм в плане парадигмы. Фичи не лежат мертвым грузом, ими очень активно пользуется сообщество.


                                                                  Но вот если вас похитили злобные цыгане индо-россияне и заставляют использовать Котлин а вам вообще в ломы, потому что Java это ваше все, то тогда и только тогда, пишите на Котлине в Java 6 стиле, вам ничего не мешает. Иначе зачем вообще переходить на Котлин?

                                                                    +1
                                                                    Интересно зачем вводить фичи в язык, которые не нужно/не надо использовать?

                                                                    Потому что такого никто не говорил. Не нужно передергивать и использовать эти фичи так, как описал автор. Вот с теми же экстеншенами, например, можно на порядок облегчить ряд задач в разработке, улучшить читаемость кода. Нужно просто понимать когда и как эту фичу применять. Написать плохой код можно и без них.

                                                                    Я пишу на C#, и треть пунктов из поста уже давно и успешно применяются в этом языке. Никто не засоряет код лишними экстеншенами, лишними перегрузками операторов, про ленивое апи коллекций и с чем его кушать могут не знать разве что стажеры/редкие джуны до первого ревью.
                                                                    +3
                                                                    Неужели плодить сущности действительно удобнее, чем держать синтаксис минималистичным?
                                                                    Мне в этом плане куда больше нравится подход Go.
                                                                      +2
                                                                      go так же плодит новые сущности под каждую задачу, если вы конечно не преобразуете типы через строчку, ну или пустыми интерфейсами грешите много
                                                                        +1
                                                                        А можно пример?
                                                                          +3

                                                                          Любой кейс, архитектурно требующий дженерик. Go предлагает россыпь костылей, плодящих типы.

                                                                            0
                                                                            Не обязательно. Ведь первый совет… Та даааам

                                                                            Review the requirements
                                                                            Step back and revisit the requirements. Review the technical or functional specification (you should have one). Do the specs really demand the use of generics? Consider that while other languages may support a design that is based on type systems, Go’s philosophy is different

                                                                              +2

                                                                              Этот совет не работает на проектах сложности чуть выше микросервиса. Страдают как раз типы, которые надо или плодить, или вынимать рефлексией и тегами.

                                                                                +3
                                                                                Ну, автор статьи это вполне серьезно предлагает, на уровне с «Consider copy-paste».

                                                                                Статья смешная во многих аспектах. Анти-паттерны приводятся как жизнеспособные стратегии для борьбы со сложностью.
                                                                                  +1

                                                                                  Да я вообще удивлен, откуда у этой истерики положительный рейтинг.

                                                                                    0
                                                                                    Ничего не могу поделать — видел как пишут обычные люди в условиях жестких дедлайнов, непонятных требований, недостаточной квалификации, необходимости десятилетиями поддерживать непонятную чертовщину итп — и это знание выгорело на сетчатке глаза, сквозь него теперь весь мир воспринимается по-другому.
                                                                                      +1
                                                                                      Я говорил про статью по ссылке, не про вашу :)

                                                                                      По вашим пунктам я постарался дать развернутый ответ ниже.
                                                                                      0
                                                                                      Каждый раз, когда я вижу эту статью, мне становится очень грустно за Go community. А ведь люди же серьезно в это верят. Как и в «ну ничего, скоро уже добавят generic'и».
                                                                                        0
                                                                                        Да я глянул слайды с доклада по го2. Такое ощущение, что синтаксис специально сделали таким, чтобы потом тыкать «видите, как неудобно! А мы сразу предупреждали, что это кактус и нинужна».
                                                                                          0
                                                                                          Да пусть какой синтаксис будет, мне кажется все лучше, чем кодогенерация из командной строки времен Java5.
                                                                                    +3
                                                                                    Не обязательно. Ведь первый совет… Та даааам


                                                                                    Меня особенно порадовал этот пример как аргумент сложности Дженериков:

                                                                                    List<dictionary<string,IEnumerable<HttpRequest>>>

                                                                                    Значит, у нас есть массив, который содержит словарь массивов, в которых лежат реквесты. То есть три уровня вложенности. Я долго старался представить бизнес-требования задачи, для которой написался этот код.

                                                                                    Увы, моей фантазии хватает только на два уровня.
                                                                                    Dictionary<string,IEnumerable<HttpRequest>>

                                                                                    — где ключ коллекции — это айдишник соединения, а значение — все реквесты, которые совершило это соединение.

                                                                                    Тем не менее я допущу, что фантазия у меня недостаточно хороша и бизнес-требования под эти три уровня есть. Как итог — мы имеем задачу с бизнес-требованиями в три уровня сложности, которая по своей сути довольно сложна.

                                                                                    К счастью, C# довольно мощный язык, который позволяет относительно легко и понятно типизировать её. На Go — это был бы типичный неподдерживаемый говнокод. Такие «вроде аргументы за, а на самом деле против» только делают языку ещё хуже.

                                                                                    Как если бы АвтоВАЗ заявляли: «заботясь о клиентах мы не ставим в автомобиль кондиционер, ведь он жрет электроэнергию и вместо этого оставляем множество щелей для проветривания».
                                                                              +2
                                                                              Из-за минималистичности приходится плодить код. Это очевидный и очень неудобный размен.
                                                                                +1
                                                                                Лучше написать пару лишних if-ов, чем плодить неудобочитаемые конструкции из знаков вопроса, восклицания и препинания.
                                                                                  +1
                                                                                  Если бы там и правда появлялась всего-то пара лишних условных операторов — я бы с вами согласился.
                                                                                    +1
                                                                                    Конкретно разворачивания вида foo?.bar?.x if-ами и заменяются. Да, больше кода — но зато есть возможность вставить ещё какую-то обработку.
                                                                                      +3

                                                                                      Если все что нужно с этим foo?.bar?.x сделать — это вернуть, то вы правы. Но в иных случаях там будет еще и две лишних переменных:


                                                                                      var x : X? = null
                                                                                      if (foo != null) {
                                                                                          val bar = foo.bar
                                                                                          if (bar != null) {
                                                                                              x = bar.x
                                                                                          }
                                                                                      }

                                                                                      Причем проблема тут не только в переменных, но и в отсутствии идиоматического способа написания: этот код можно написать 6 разными способами (два способа с ветками else и 1 без них умножить на переменную bar, которая может быть как внутри, так и снаружи), и это только нормальные способы! А ведь есть еще и вот такие:


                                                                                      var x : X?
                                                                                      if (foo == null) {
                                                                                          x = null
                                                                                      } else {
                                                                                          x = null
                                                                                          val bar = foo.bar
                                                                                          if (bar != null) {
                                                                                              x = bar.x
                                                                                          }
                                                                                      }

                                                                                      На этом фоне достоинство foo?.bar?.x еще и в том, что такое написание единственно, и к нему можно просто привыкнуть, вместо того чтобы раз за разом разбирать очередной порядок написания условных операторов.

                                                                              +3
                                                                              А как вам такое: в Kotlin нет checked exceptions. А в JVM-реальности они есть.


                                                                              Таки в Java-реальности или в JVM?
                                                                                0
                                                                                Поправил
                                                                                +4
                                                                                Ещё немного:
                                                                                1) котлин хочет усидеть на 3 стульях (js, jvm, native) сразу, и это несовместимо с совместимостью с джавой (put intended). Логика простая: появлятся pure kotlin библиотеки, которые будут частично дублировать функционал уже существующих, но их можно будет использовать в мультиплатформенных проектах. Это приведет к расслоению экосистемы, так как все эти библиотеки будут развиваться независимо друг от друга. Что, в свою очередь, убивает совместимость с джавой; речь не про техническую возможность вызвать код, а про удобство этого процесса.

                                                                                Пример такого расслоения — scala, где либо есть отдельные java-api, либо библиотеку невозможно использовать из джавы. История повторяется?

                                                                                Само по себе это разделение не является плохой вещью, но исчезает позиционирование языка как «better java». Что, в случае котлина, является основной selling point для не-андроидоводов.

                                                                                2) туда же корутины и так называемый kotlin-dsl — библиотека, фундаментально построенная на этом, не будет использоваться из джавы. За примером далеко ходить не надо — ktor пишут лучшие котлинисты мира, но java api там нет.

                                                                                3) mobile-first развитие => отсутствие плюшек из более новых jvm (8+) в сгенеренном байткоде.
                                                                                  +2
                                                                                  Ничего, по первому пункту есть пример МС с их .Net Standard, которым Jet brains может воспользоваться. Сейчас всё более менее популярные .net библиотеки скомпилированы так, чтоб и можно было использовать на максимальном числе платформ.
                                                                                    0
                                                                                    Не вижу, Как джава может использовать стандарт. По сути стандарт — это множество C# типов с пустой реализацией, которая компилится в IL. Джава в IL компилиться не будет.

                                                                                    Сделать свой стандарт ничего не мешает, но мне кажется это тоже процесс небыстрый.
                                                                                      +1
                                                                                      Джава компилируется в байткод.

                                                                                      Сделать свой стандарт ничего не мешает, но мне кажется это тоже процесс небыстрый
                                                                                      ну у .Net тоже не сразу получилось. Сначала был PCL.
                                                                                    +2
                                                                                    А разве <kotlin.compiler.jvmTarget>1.8</kotlin.compiler.jvmTarget> не под 8-ку собирает?
                                                                                      +1

                                                                                      Собирает, но без "мелочей" типа invokedynamic (сейчас анонимные классы, по-старинке) и всего остального, что недоступно на текущей андроид jvm.


                                                                                      Возможная аргументация: тогда будет весьма проблематично распостранять библиотеки. Скажем, написал кто-то утилиту под 11 jvm, с ранее несуществующими фичами, залил jar, и при попытке использовать на старой jvm эти самые ранее недоступные фичи будет ошибка. Даже не при попытке, а при подгрузке байткода.


                                                                                      Это решается (можна снова глянуть на пример скалы), но ценой некоторого удобства пользователя. Ну и таких фич немного. Тем не менее, "android-first" развитие, если в 12 jvm выпустят что-то этакое, то котлин очень нескоро будет генерировать соответствующий байткод.

                                                                                    +1
                                                                                    Оказалось, в C++ можно не писать return в методе, который согласно сигнатуре должен что-то возвращать. Это не синтаксическая ошибка согласно стандарту, а undefined behavior. Соответсвенно, программа в рантайме падает с произвольной ошибкой. Чудесный язык — в нем есть специальный синтаксис для неработающих методов.

                                                                                    Я как-то натыкался в коде на такое:
                                                                                    int something;
                                                                                    ...
                                                                                    if (blabla...) {
                                                                                       return x;
                                                                                    } else {
                                                                                       return something;
                                                                                    }
                                                                                    
                                                                                      +1
                                                                                      Извините, за может тупой вопрос. Я пока совсем начинающий. А что в этом коде не так? Или все дело в том, что else можно лишится?
                                                                                        +1

                                                                                        something не инициализирована и содержит мусор?

                                                                                          +1
                                                                                          Будет warning при компиляции. И потом, есть же загадочные ..., something может быть инициализирован там
                                                                                        +1
                                                                                        Присоединяюсь к вопросу. Тернарный оператор был бы уместнее, но и так, кажется, всё ок
                                                                                          +1
                                                                                          Возможно я не очень четко это показал, но там возвращается значение неинициализированной переменной. Т.е. в определенной ветке кода функция возвращает тупо «что-то». Причем программист это понимал, что это будет «что-то» и даже переменную назвал соответствующим образом. Функция, иногда возвращающая рандомный мусор вместо ответа — как тебе такое Илон Маск?
                                                                                            +1
                                                                                            Более весело то, что хороший компилятор может эту ветку из кода выпилить. И безусловно возвращать x.
                                                                                        +5
                                                                                        Прошу извинить за оффтом, но недавно просто читал, и напомнило из книги Л.Л.Васильева «Экспериментальные исследования мысленного внушения»:
                                                                                        другой консультант (проф. М. В. Шулейкин), напротив, скептически относился к самой проблеме и подвергал суровой критике все наши опыты. Этим он принес делу большую пользу.
                                                                                          +3
                                                                                          Если в общем — в котлине можно все писать в джава стиле. Да это ущербно, да так делают только новички, но — можно. Так что ты всегда можешь обмазаться if вместо ?.let.

                                                                                          Теперь по пунктам:

                                                                                          it -> foo(it, 1); }.map { it -> bar(it, 2); }.filter { it -> it.getBaz() > 0; }

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

                                                                                          
                                                                                          fun List<String>.filterValid(): List<String>
                                                                                          fun List<Int>.filterValid(): List<Int>

                                                                                          Можно было просто написать инлайн класс и на него повесить экстеншн. И да, это и нужно в том числе для того, чтобы решить проблему с кучей экстеншнов в коде. И опять же — ну не нравится — не используй. Всегда можно написать top-level функцию и не мучаться.

                                                                                          Давайте ещё навалим про библиотеку. Нафига в стандартную библиотеку языка, который поддерживает дата-классы, включили пары? Это ж прямое поощрение плохого кода.

                                                                                          Ну да, делали по сути для двух вещей, для destructuring declarations и для того, чтоб olegchir писал плохой код. В принципе сразу убили двух зайцев одним выстрелом.

                                                                                          Но стоит только поменять определения функций на вот такие:

                                                                                          Явно указать нельзя разве? Или мешает чего?

                                                                                          В общем как итог — вброс конечно же удался, но в целом котлин предоставляет необходимую гибкость нормальным разработчикам и не ставит перед собой цель забить всех в рамки, где шаг влево, шаг вправо — расстрел ошибка компилятора. По аналогии можно предъявить тому же Калашникову, за то что обезьяна случайно прострелила себе колено, не разобравшись как это работает. Но этого никто не делает, потому что на обезьян не рассчитано.

                                                                                            +2
                                                                                            Так что ты всегда можешь обмазаться if вместо ?.let

                                                                                            Не всегда, подобные конструкции приходится применять, когда идёт работа с nullable мутабельным полем, т.к. компилятор считает, что они могли измениться после чтения и стать null, не оставляя никакой возможности сказать ему, что разработчик сам заботиться о синхронизации доступа к таким полям. На мой взгляд это самая спорная фича компилятора. Вот тут пытался обсуждать, если интересно подробнее. В итоге обмазываться приходится всеми этими ?.let.
                                                                                              –1
                                                                                              не оставляя никакой возможности сказать ему, что разработчик сам заботиться о синхронизации доступа к таким полям.

                                                                                              О, да ты еще и про котлиновские контракты не слышал! Грустно жить, когда все достижения человечества проходят мимо?
                                                                                                +4
                                                                                                Слышал. А к чему это здесь? Разве это как-то поможет обозначенной проблеме?
                                                                                                  +2
                                                                                                  Поможет, как раз тем, что можно явно сказать компилятору что в nullable переменной гарантированно будет не null
                                                                                            +1
                                                                                            Если честно, думаю, что повторю предыдущих комментаторов, но тем не менее…
                                                                                            Котлин даёт одинаковый API для коллекций и сиквенсов, из-за чего люди злоупотребляют цепочками map/filter на коллекциях

                                                                                            Проблема программиста же. Если ты не понимаешь, как что-то работает под капотом, или это работает неожиданно, то имеет смысл винить себя и того, кто ревьювил код (если ревью было).
                                                                                            Котлин форсит использование it, что приводит к нечитаемому коду.

                                                                                            Все нормально читается. Неявная подстановка названия итерируемой переменной вполне удобна. Если уж не нравится, то в требования к коду вводить обязательное использование лямбд с именованным(и) параметром(ами).
                                                                                            Цепочки вроде ?.let { foo(it); }?.let { bar(it); }

                                                                                            Их применение зависит от ситуации. Если вам не важно, в каком месте возник null, то вы напишете так, в противном случае шансы увидеть подобный код после адекватного ревью будут достаточно низкими.
                                                                                            Он должен думать обо всех экстеншн-методах, которые любые люди могут добавить в тот же класс?

                                                                                            Вы перевернули все с ног на голову. Я как автор класса используемой библиотеки о таком задумаюсь с очень малой долей вероятности. Если кто-то экстендит мой класс — его право. Однако, изменение данного класса — моя привилегия и если вы хотите продолжать использовать мою библиотеку, то либо меняйте свои расширения, либо используйте старую версию.
                                                                                            Библиотека местами не продумана. Например, reduce

                                                                                            А вот тут я соглашусь с вами. Мне гораздо удобнее вариант, когда аккумулятор ты создаешь сам. К примеру, как это реализовано в Clojure.
                                                                                            Нафига в стандартную библиотеку языка, который поддерживает дата-классы, включили пары? Это ж прямое поощрение плохого кода.

                                                                                            Опять же, если код прошел какое-либо ревью, либо не проходил его (если так принято), то это проблема организации бизнес-процессов компании / квалификации ревьюверов и т.д.
                                                                                            p.s. в данном посте обращение «ты» использовано не в панибратских целях, просто изначально свою мысль сформулировал таким образом.
                                                                                              +5

                                                                                              Если не вдаваться в детали, описанные автором, то можно согласиться с общим месседжем: код на Kotlin-е становится вцелом менее понятный, чем на Java, особенно при наличии определенного знакомства с языком. При первом знакомстве все пишут как на Java, поэтому все достаточно просто. Но узнав немного язык, разработчик начинает теряться в возможностях, код становится более плотным и лаконичным, но менее структурированным. В частности постоянно возникают вопросы:


                                                                                              • Один класс на файл или несколько классов в файле?
                                                                                              • Как правильно использовать пакеты?
                                                                                              • Когда использовать статические определения вне классов, а когда делать их в компаньонах?
                                                                                              • Использовать экстеншн-методы, или методы класса?
                                                                                              • Делать ли инициализацию полей при объявлении, или выносить отдельно в init{} — блок? И вообще в Котлине нет четкой границы между определением и поведением. При определении поля можно его и проинициализировать объектом, и сконфигурировать при помощи .apply(), и там же навесить хендлеров и листенеров. Структура класса превращается в кашу.
                                                                                              • Нагромоздить однострочник или разбить все по действиям?
                                                                                              • Для операции с объектом переопределить сеттер на свойство или создать отдельный вменяемый метод?
                                                                                              • Общие рекомендации по стилю.
                                                                                              +11
                                                                                              Автор не понял почему котлин взлетел на андроид — этот язык отвязал программистов от версии jvm, убрал вербозность языка java, встроил самые популярные паттерны программирования в сам язык, добавил возможности dsl которые очень удобно использовать для всевозможных конфигураторов. Хоть котлин и рекламирует 100% совместимость с java но это верно лишь для использования java кода в котлин коде, обратно же никто особо не парится, потому как это дорога в один конец, более высокоразвитый язык поглощает более простой, поэтому не ждите что котлин код будет красиво вызываться из java, совместимость лишь для того чтобы не потерять уже готовый код, но не новый.
                                                                                                +1
                                                                                                Взлетел — относительное понятие… У Котлина есть преимущества, что вы описали, но код реально превращается в непонятную кашу для ревью и для обычного прочтения. А если тем более не будет совместимости с java / android, то дорога для него пойдет в обратную сторну.
                                                                                                  +1
                                                                                                  Не будет. Как правильно выше сказали — «наличие возможности именовать переменные как угодно, не доставляет проблем».

                                                                                                  Многое из того что есть и удивляет в котлине есть в C# и у нас с этим нет трудностей. Напротив — код очень выразителен и краток. Уверен вам тоже самое скажут и Swift — программисты.
                                                                                                  +1
                                                                                                  этот язык отвязал программистов от версии jvm

                                                                                                  Ничего подобного. Внезапно выяснилось, что некоторые конструкции валятся в runtime на 6-ом андроиде, при этом работают на 7 и выше.
                                                                                                  Например, мы в команде столкнулись с тем, что map.forEach { (a, b) -> foo() } — матчится в Map.Entry<K, V> (который есть в 6-ой Java), а map.forEach { a, b -> foo() } в BiConsumer<? super K,? super V> (которого нет в 6-ой). При это проект собирается абсолютно без ошибок.
                                                                                                    +2
                                                                                                    Это не вина котлина, вы использовали java api которое есть в target sdk, но нет в min sdk, а обход ошибки как раз в использовании котлин апи вместо java api
                                                                                                  +7
                                                                                                  А IDE плохо, когда ты едешь в поезде и видишь, что свинговый жабоинтерфейс высасывает из ноутбука батарейку как вампир.

                                                                                                  Белые люди в поездах не кодят, они в поездах отсыпаются или, в худшем случае, кину смотрят.

                                                                                                    +2
                                                                                                    Котлин не читал, но после этой статьи осуждаю. Однако вынужден вступиться за C++. Да, в сферическо-вакуумном C++ отсутствие return это UB, но любой уважающий себя и пользователя компилятор имеет соотв. диагностику, которую можно легко превратить в ошибку. Ну а не использующие такие компиляторы или отключающие варнинги индивиды получают то, что заслужили.
                                                                                                      +3

                                                                                                      Имхо такую статью можно про любой язык написать. Так советую прежде чем осуждать "почитать".

                                                                                                        +1
                                                                                                        Ну шутка же. Парафраз «Пастернака не читал, но осуждаю».
                                                                                                        +2
                                                                                                        ИМХО как раз пункт про С++ один из немногих валидных.
                                                                                                        +20
                                                                                                        1. Когда я приезжаю на коне к моему бару, мне легко поставить лошадь у поилки. Машину ставить решительно некуда — непродуманная конструкция автомобиля, нужно было делать авто в форме лошади
                                                                                                        2. Я мог бросить лошадь посреди поля, и она сама ела бы траву. Машины нужно заправлять дурацким топливом — что за бред, кто вообще на это пойдет
                                                                                                        3. Когда я ездил на коне, я носил шпоры. Теперь шпоры мешают мне нажимать на педали. Их идиотская форма не смогла предусмотреть такую очевидную вещь, которой пользуются все наездники
                                                                                                        4. Машина требует дороги! На лошади я могу залезть на любой холм, для машины же требуется специально готовить трассу, заниматься освещением, инфраструктурой и остальными вещами. Раньше я мог остановиться посреди поля и заночевать с конем, а теперь привык пользоваться ортопедическим матрасом и 3-звездной гостиницей.
                                                                                                        Разница этого рассказа и спора между Kotlin-Java в том, что Kotlin забирает очень мало, но дает очень много нового и не отказывается от поддержки старого. Впрочем в статье жалоба «мне так непривычно, а значит плохо» — прослеживается слишком явно.
                                                                                                          +1
                                                                                                          нужно было делать авто в форме лошади

                                                                                                          Так ведь сделали. Мотоцикл называется :)
                                                                                                            +1
                                                                                                            ага, подковы вешать некуда и еще оно навоз не выделяет. Жалкая пародия на оригинал
                                                                                                              +1
                                                                                                              подковы вешать некуда

                                                                                                              чем не подкова? http://drive2moto.ru/uploads/blogs/14525/orig-img1402a.jpg

                                                                                                                +1
                                                                                                                гвоздь не забьеш! требуется высокотехнологичное производство!
                                                                                                                  +3
                                                                                                                  высокотехнологичное производство

                                                                                                                  как только напильник не обзовут

                                                                                                          +11

                                                                                                          Раз уж автор попросил в Kotlin Community о конструктивной критике по сути, то она у меня есть.
                                                                                                          По пунктам с цитатами из статьи:


                                                                                                          Добро пожаловать под кат
                                                                                                          В Котлине за любым простым выражением может стоять сколь угодно сложный код из-за всяких умностей вроде перегрузки. Без IDE ничего не поймёшь. А IDE плохо, когда ты едешь в поезде и видишь, что свинговый жабоинтерфейс высасывает из ноутбука батарейку как вампир.

                                                                                                          Начать с того, что в чтении/написании Java кода без IDE тоже далеко не уедешь. Что касается самой перегрузки операторов, то в ней особо проблем нет, это всего лишь другой способ объявления методов, который позволяет единообразно писать выражения независимо от типов данных, над которыми эти выражения вычисляются.
                                                                                                          Классический пример — BigDecimal в Java:


                                                                                                          BigDecimal hundredAndOne = BigDecimal.ONE.add(BigDecimal.TEN.multiply(BigDecimal.TEN));

                                                                                                          То же в Kotlin:


                                                                                                          val hundredAndOne = BigDecimal.ONE + BigDecimal.TEN ** BigDecimal.TEN

                                                                                                          Котлин даёт одинаковый API для коллекций и сиквенсов, из-за чего люди злоупотребляют цепочками map/filter на коллекциях, создавая кучу промежуточных неленивых копий. Стримы в джаве специально введены для различия между ленивой и неленивой коллекцией. Да, есть инспекция в IDE для этого — потому что инспекции призваны исправлять недостатки языков.

                                                                                                          В Java, чтобы получить список целых чисел, каждое из которых на 1 больше соответствующего числа из исходного списка нужно будет сделать так:


                                                                                                          List<Integer> plusOne = xs.stream().map(x -> x + 1).collect(Collectors.toList());

                                                                                                          В Kotlin:


                                                                                                          val plusOne = xs.map { it + 1 }

                                                                                                          При этом быдлокодеры люди прекрасно в Java делают collect на каждый чих (на прошлом Joker про это был один из докладов) и никакая IDE инспекция им об этом не говорит.


                                                                                                          Котлин форсит использование it, что приводит к нечитаемому коду. Что-нибудь типа seq.map { it -> foo(it, 1); }.map { it -> bar(it, 2); }.filter { it -> it.getBaz() > 0; }. Что это вообще было?

                                                                                                          Действительно, что это было такое? Если уж использовать it, то не надо стрелочек тогда (рак из точек с запятой в конце каждой строки тоже можно убрать). Надо так:


                                                                                                          seq.map { foo(it, 1) }.map { bar(it, 2) }.filter { it.getBaz() > 0 }

                                                                                                          Если серьёзно, то в лямбдах (они обычно очень короткие) параметры тоже именуют коротко. Давать длинное имя единственному аргументу, который тут же и используется — много чести. По использованию и так понятно, что в нём, либо же для задачи это не важно.


                                                                                                          Цепочки вроде ?.let { foo(it); }?.let { bar(it); } — это вообще ад и должны быть запрещены в декларации о правах человека. И это считается идиоматично, Карл. В отличие от нормального if. Читать такой код невозможно.

                                                                                                          Да, с if наверно читаемее:


                                                                                                          arg?.let { foo(it) }?.let { bar(it) }

                                                                                                          будет равносильно


                                                                                                          if (arg != null) {
                                                                                                              val foo = foo(arg)
                                                                                                              if (foo != null) {
                                                                                                                  bar(foo)
                                                                                                              } else null
                                                                                                          } else null

                                                                                                          От интеропа с джавой кровь идёт из глаз. А тут всякие JvmStatic и JvmName, и код превращается в цирк с конями.

                                                                                                          Тут соглашусь, использование Kotlin из Java достаточно не удобно просто потому, что очень многих фич Kotlin нет, вот и приходится лишние приседания делать. BTW, обычно Java библиотеки используются из Kotlin, а не в обе стороны. Очень странен проект, где оба языка будут на равных правах присутствовать.


                                                                                                          А как вам такое: в Kotlin нет checked exceptions. А в Java-реальности они есть. Отряд специального назначения «Боевые протезы» имеет честь представить новый самоходный костыль @Throws:

                                                                                                          Да, в Kotlin выпилили то, что даже в мире Java уже считают антипаттерном (checked exceptions). Для interop сделали аннотацию. В чём проблема?


                                                                                                          Автоматические геттеры/сеттеры с добавлением английского слова get и первой буквой проперти в большом регистре (видимо, в локали ENGLISH? Ведь регистр букв системно-зависим) — это страшно.

                                                                                                          Чем страшно-то? Геттеры/сеттеры генерируются согласно устоявшимся в Java мире конвенциям.


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

                                                                                                          Экстеншн-методы не загрязняют никаких интерфейсов. По факту это просто статические хэлпер методы, которые вызываются через точку.


                                                                                                          Библиотека местами не продумана. Например, reduce.

                                                                                                          reduce так работает во всех языках, где он есть. Я верно понял, что и в Haskell (foldr1, foldl1), и в ruby, и в python они не продуманы, если верить автору?


                                                                                                          Давайте ещё навалим про библиотеку. Нафига в стандартную библиотеку языка, который поддерживает дата-классы, включили пары?

                                                                                                          Во-первых для mapOf(...), да и вообще, для тех же целей, для которых в Java есть Map.Entry


                                                                                                          Очень странный момент — возможность не указывать возвращаемый тип метода (особенно публичного).

                                                                                                          Тип выводится только для методов, которые объявлены как выражение. Если метод абстрактный и тип не указан (в публичном интерфейсе, например), то он Unit по умолчанию. Если нужен не Unit — придётся в интерфейсе явно указать, так что проблема надуманная, как мне кажется. BTW, конвенции по коду в языках с выведением типов (Haskell, Scala, Kotlin и т.д.) требуют указывать их для публичного API


                                                                                                          Резюмирую: всё как-то мимо с критикой в статье. Похоже автор плохо разобрался в объекте своей критики.

                                                                                                            0
                                                                                                            А я пожалуй соглашусь с последним пунктом, не писать тип функции имеет смысл только на уровне лямбды. Даже в хаскеле емнип не констрейнтить типы функции считается дурным тоном.
                                                                                                              +1
                                                                                                              Даже если это внутренняя, приватная, функция?

                                                                                                              А так-то да, не писать тип проэкспортированных из библиотеки функций — это даже не дурной тон, за такое морду бить надо.
                                                                                                                +1
                                                                                                                В Хаскеле дурным тоном считается не аннотировать типы публичных деклараций (тех, что экспортируются из модуля). Остальное по желанию.
                                                                                                                Да, кстати, в Хаскеле вообще нет различий между лямбдой и именованной функцией, равно как и нет различий между функциональными типами данных и остальными. Более того, так как он тотально ленив, то то, что по типу данных является числом, представляется в памяти как thunk (что-то вроде Supplier в терминах Java). Число вместо него в памяти появляется только тогда, когда понадобилось в других вычислениях.
                                                                                                                  +1
                                                                                                                  Да, но если вспомнить, что большинство классов публичные (люди не парятся с internal), то все публичные методы это экспортируемые символы, со всеми вытекающими.

                                                                                                                  Правда, я не вижу проблем проставлять значения типам всем функциям, чтобы быть уверенным, что в случае ошибки она не пролезла через 10 уровней коллстека откуда-то из кишков.
                                                                                                                    +1
                                                                                                                    До рантайм ошибки несовместимости типов не пролезут. Если у функции выведен, а не указан явно тип возвращаемого значения (Unit для функций, декларированных как блок; тип выражения для функций, декларированных как выражения), то это не значит, что его нет.
                                                                                                                    В любом случае, код, использующий функцию, не скомпилируется, если ожидаемый тип возврата не совместим с выведенным по телу функции.
                                                                                                                    То же верно и для пулбичных val/var деклараций.
                                                                                                                      +1
                                                                                                                      Я не про рантайм. Я про то, что если я поменял код, и что-то сломалось, то я точно знаю, что либо поломался код в функции Х, либо в той функции, которая из Х вызывается. Варианта, что вывод поменял типы у десятка функций, в таком случае, нет.
                                                                                                              +4

                                                                                                              Вы сейчас описали фичи C#:


                                                                                                              вроде перегрузки

                                                                                                              Котлин даёт одинаковый API для коллекций и сиквенсов,

                                                                                                              в Kotlin нет checked exceptions

                                                                                                              Автоматические геттеры/сеттеры

                                                                                                              Экстеншн-методы

                                                                                                              форма без identity кидает исключение для пустой коллекции.

                                                                                                              Все они добавлены для того, чтобы не плодить тысячи строк boilerplate-кода. Вы, случайно, не из тех, кто был против var, ведь нипанятнаже?


                                                                                                              вроде перегрузки

                                                                                                              Напомню, что в Java есть перегрузка + для строк, как special case, да и [index] имеет логику внутри, а не просто складывает указатели. Вы используется велосипедный конкатенатор строк, чтобы, не дай бог, не пропустить выделение памяти?


                                                                                                              Перегрузка гарантирует унификацию. .get(...) / .elementAt(...) / .charAt(...) заменяются на [...]. Наличие обращения к методу вам ничего особо не даёт — в большинстве случаев вы обращаетесь как раз к геттеру / сеттеру, даже если там внутри простое присваивание / чтение поля. В значительной части случаев, реализация скрыта из интерфейсом — знание факта вызова ничего не даёт, в нём может происходить всё, что угодно.


                                                                                                              Автоматические геттеры/сеттеры

                                                                                                              это страшно

                                                                                                              // call getFirstDayOfWeek()

                                                                                                              • Чем может помочь знание того, что при обращении к объекту вызывается метод, а не происходит обращение к свойству с неявным вызовом метода?
                                                                                                              • Во всех языках с перегрузкой полагают, что любое обращение к стороннему объекту — вызов метода.
                                                                                                              • В большинстве случаев, для объектов с поведением, как раз плодятся методы вида get* / set* и унификация доступа к ним снижает количество визуального мусора. x.Width *= 2 вместо x.setWidth(x.getWidth()*2).

                                                                                                              Ведь регистр букв системно-зависим

                                                                                                              Вы слышали о такой вещи, как инвариантная локаль?


                                                                                                              @JvmName("filterValidInt")

                                                                                                              Да, костыль над type erasure, чтобы иметь возможноть перегружать методы, как в языках с нормальной vm, а не плодить множество разных имён, но при этом иметь читаемый код в Java, а не генерировать суффикс-хэш автоматически.


                                                                                                              Экстеншн-методы загрязняют публичный интерфейс такими вещами, о которых автор и подумать боялся.
                                                                                                              Работа экстеншн-методов возможна, даже если автор специально сделал финальный класс, явно показав, что не хочет сторонних расширений
                                                                                                              Он должен думать обо всех экстеншн-методах, которые любые люди могут добавить в тот же класс?

                                                                                                              Это не так работает. Extension-методы — синтаксический сахар, после компиляции они становятся обычными вызовами статических методов, не влияя на целевой тип. Доступа к private / protected членам у них тоже нет.

                                                                                                                +3

                                                                                                                Extension-методы — для тех, кто в курсе что такое "behavioral mixin". Я бы сказал, что в этом месте автор критикует то, чего не понимает.
                                                                                                                В остальном полностью с вашим комментарием солидарен.

                                                                                                                +3
                                                                                                                Без IDE ничего не поймёшь.

                                                                                                                без IDE в любом мало-мальски сложном приложении фиг поймёшь


                                                                                                                А IDE плохо, когда ты едешь в поезде и видишь, что свинговый жабоинтерфейс высасывает из ноутбука батарейку как вампир

                                                                                                                Jetbrains позаботился о батарейке твоего ноутбука и сделал режим "Power safe mode". Более того — он ещё и настраиваемый.

                                                                                                                  +1
                                                                                                                  Без какого IDE? В очень больших проектах, продвинутый редактор может быть даже полезнее IDE и тормозит меньше.
                                                                                                                    +2
                                                                                                                    Без какого IDE?

                                                                                                                    Без любого, умеющего делать подсветку/проверку синтаксиса, форматирование кода и запуск на выполнение. Хотя без последнего тоже можно жить, держа рядом консоль.
                                                                                                                    Arduino IDE вон тоже IDE, хотя по сути это просто "продвинутый редактор" — даже autocomplete нет

                                                                                                                      +1
                                                                                                                      Если речь о понимании проекта, то я бы выделил подстветку, функции Go To Definion/Implementation и поиск использований по проекту(семантический, а не тупой перебор), а так же возможность пробежаться глазами по структуре файла. Поиск, разумеется, ленивый должен быть. Это первое, что пришло в голову.
                                                                                                                      Настроить всё это достойно в «продвинутом редакторе» дело не лёгкое и проблематичное. И всё, что это даст — аналог IDE с чуть большей скоростью в ущерб функционала, поскольку добиться такого же качества едва ли выйдет.
                                                                                                                    +2
                                                                                                                    Извините меня, но в чём смысл статьи? В том, что на котлине можно написать нечитаемую дичь? Дак это и на джаве можно и на любом другом языке.

                                                                                                                    А вообще в 2018 не писать андроид приложения на котлин это моветон.
                                                                                                                      +2
                                                                                                                      Большинство из написанного есть в Groovy, и мне нравится. Половина из этого — плюсы, а не минусы.
                                                                                                                        –2
                                                                                                                        Это провоцирует людей писать нечленораздельную лапшу, в которой и ничего не понятно.

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

                                                                                                                        P.S. А гетеры/сетеры-то чем не понравились, я так и не понял?
                                                                                                                          +1

                                                                                                                          Есть интересная статья (и единственная за тоннами хайпа) — Kotlin vs Java The Whole Story. Там сделана попытка обьективно оценить целесообразность перехода на Котлин.

                                                                                                                            –6
                                                                                                                            Поэтому я отправился на Курсеру изучать курс Kotlin for Java Developers и начал читать книжку
                                                                                                                            «Разработчикам» с такими скиллами нужно в детсад идти доучиваться, а не стати писать. Нормальный разработчик просто берет и пишет на Котлине, особенно после Джавы, там нечего изучать.

                                                                                                                            Вообще, выбор между Котлином и Джавой это как выбор между гомосексуализмом и зоофилией. Непонятно что хуже.

                                                                                                                            У разрабов Котлина стояла задача исправить второй по счету крупный недостаток Джавы — многословность. (Первый — это то что Джава JVM-based, как вы понимаете, он не фиксится). И они с ней вроде справились, но при этом добавили своей.

                                                                                                                            Итак, по пунктам:

                                                                                                                            1. Сompanion object — че это вообще за концепция такая? Почему я вместо
                                                                                                                              class C {
                                                                                                                                  public final static int CONST = 10;
                                                                                                                              }; 
                                                                                                                              я вынужден писать
                                                                                                                              class C {
                                                                                                                                   companion object{
                                                                                                                                        const val CONST = 10
                                                                                                                                   }
                                                                                                                              }
                                                                                                                              

                                                                                                                              Какой извращенец это придумал? Какой вообще в этом смысл? Какие преимущества несет?
                                                                                                                            2. Сделали чтобы if возвращал значение, но убрали тернарный оператор. Нахрен мне вообще этот if? Тернарный оператор в разы удобнее.
                                                                                                                            3. var/val. Почему не let\let mut? Нет никакого стимула использовать var. В след версии добавьте van,vam и т.п.
                                                                                                                            4. Функции по умолчанию public. WAT? Т.е вы по умолчанию делаете final class, final function, но при этом я должен писать везде private, где логика?
                                                                                                                            5. lateinit — костыль размером с мамашу автора. Его добавили с целью избавиться от NullPointerException, в результате место него получаем UninitializedPropertyAccessException. Только nullable хотябы проверить на null можно, а lateinit нет. Поменяли стул с пиками пики на другой. Шило на мыло.
                                                                                                                            6. return@listener — это вообще без коментариев.

                                                                                                                            И таких вещей в Котлине навалом. Без IDE на нем невозможно писать. В С++ наверное синтаксических загонов меньше.

                                                                                                                            Но если серьезно, то для Андроида выбор между Джавой и Котлином очевиден. В Джаве нет map/filter/reduce(нужно тащить ретростримы), в ней приходится писать жуткий бойлерплет с findViewById и гугл походу окончательно забил на поддержу новых версий.

                                                                                                                              +1
                                                                                                                              1. Не забывайте что можно писать и
                                                                                                                              const val CONST = 10

                                                                                                                              class C {
                                                                                                                              }


                                                                                                                              5. Можно
                                                                                                                              if (::myLateinitField.isInitialized) {}
                                                                                                                              +9
                                                                                                                              Я очень далёк и от Явы и от Котлин, но вот за это:
                                                                                                                              Работа экстеншн-методов возможна, даже если автор специально сделал финальный класс, явно показав, что не хочет сторонних расширений.
                                                                                                                              Котлину можно простить всё. И этого очень не хватает в каком нибудь Go. Ибо меня, как программиста, очень мало интересует мнение автора библиотеки.
                                                                                                                                +9

                                                                                                                                Спасибо за быстрое и лаконичное введение в фичи Kotlin-а от лица всех C#-разрабов :)
                                                                                                                                Как шарпист заявляю: более половины из описанных "странностей" мне очевидны. Kotlin делает так, чтобы писать на Java шарписту стало не отвратительно :) Тут, конечно, есть ещё над чем поработать, но JetBrains движутся в правильном направлении.

                                                                                                                                  +2
                                                                                                                                  У меня такое ощущение, что вокруг Котлина немного искусственно нагнетается шумиха на этом сайте. Нет?

                                                                                                                                  Посмотрите на том же тостере сколько вопросов по Джаве и сколько по Котлину — почти ноль.
                                                                                                                                    +2
                                                                                                                                    Tiobe на днях обновился, Котлин по прежнему рядом с хаскелем на задворках. В целом да, ощущение, что шумиха, в основном, в русскоязычном сообществе. И то лишь потому, что котлинисты громкие, а джависты просто сидят и работу работают.
                                                                                                                                      +1
                                                                                                                                      gradle скрипты кстати начиная с пятой версии можно на котлине писать, все примеры на двух языках идут. Так что определенно есть прогресс и не малый
                                                                                                                                    +7

                                                                                                                                    Дожили! В JugRu теперь платят людям, чтобы они ругали Котлин!

                                                                                                                                      0
                                                                                                                                      Лютый зашквар,
                                                                                                                                      Трэш и хардкор
                                                                                                                                      Струпья ю-трупа
                                                                                                                                      Жрёт хайпожор.

                                                                                                                                      (с) Louna, «Шум»
                                                                                                                                      +3
                                                                                                                                      А IDE плохо, когда ты едешь в поезде и видишь, что свинговый жабоинтерфейс высасывает из ноутбука батарейку как вампир.
                                                                                                                                      И как часто вы работаете в поезде?
                                                                                                                                      Кстати, об IDE. Насколько хороша поддержка Kotlin в IntelliJ IDEA? Она действительно лучше, чем для Java? Есть большие сомнения.
                                                                                                                                      Ну это аргументация уровня Рен-тв. Совпадение? Не думаю.
                                                                                                                                      Цепочки вроде ?.let { foo(it); }?.let { bar(it); } — это вообще ад

                                                                                                                                      Нормально будет, если в цепочке только один такой оператор. И то от безысходности, если не можешь изменить код библиотечной функции. Рекомендую избегать смешивать nullable и nonNullable типы.
                                                                                                                                      Работа экстеншн-методов возможна, даже если автор специально сделал финальный класс, явно показав, что не хочет сторонних расширений.
                                                                                                                                      Экстеншн методы не про наследование, а про расширение функционала. Финальный класс так и останется финальным. Его никто не наследует и не заберётся в кишки protected.
                                                                                                                                      что будет, если в следующей версии библиотеки автор добавит методы с теми же именами, но с другим возвращаемым типом?
                                                                                                                                      Вам стоит ещё раз почитать документацию. Сработает оригинальный метод.
                                                                                                                                      Да или хоть null вернуть, раз уж это null-friendly язык.

                                                                                                                                      Ага, а потом опять работать с цепочками ?.let { }?.map { }?.filter { }
                                                                                                                                      fun c(check: Int) =

                                                                                                                                      Пожалуйста, не делайте так. Это синтаксис для однострочной лямбда функции.
                                                                                                                                        +5

                                                                                                                                        По пунктам:


                                                                                                                                        В Котлине за любым простым выражением может стоять сколь угодно сложный код из-за всяких умностей вроде перегрузки.

                                                                                                                                        И? То, что вы не знаете как ведёт себя тот или иной оператор в данном конкретном случае — ваша вина. Язык тут ни при чём. RTFM, наконец!


                                                                                                                                        Без IDE ничего не поймёшь.

                                                                                                                                        А то ж вы в проекте на Java/PHP/C#/C++ много чего без IDE поймёте.


                                                                                                                                        А IDE плохо, когда ты едешь в поезде и видишь, что свинговый жабоинтерфейс высасывает из ноутбука батарейку как вампир.

                                                                                                                                        Ну тут мне остаётся только посочувствовать Java-разработчикам (уж не знаю — то ли потому что на поездах ездят, то ли потому что IDE отжирает столько батареи) :)


                                                                                                                                        Котлин даёт одинаковый API для коллекций и сиквенсов, из-за чего люди злоупотребляют цепочками map/filter на коллекциях, создавая кучу промежуточных неленивых копий.

                                                                                                                                        Меня удивляет ваше стремление решать что другие люди должны делать и чего не должны. Вообще-то это неприлично. Вы злоупотребляете? Нет? Ну вот и ладушки. Остальные, полагаю, сами разберутся без вашего мнения.


                                                                                                                                        Котлин форсит использование it

                                                                                                                                        … а вы всё никак не хотите научиться правильно его использовать facepalm


                                                                                                                                        Цепочки вроде ?.let { foo(it); }?.let { bar(it); } — это вообще ад и должны быть запрещены в декларации о правах человека.

                                                                                                                                        Вот опять, обратите внимание. Откуда в вас это стремление запрещать что-либо всем людям сразу, если конкретно вам непонятна эта конструкция? Избавляйтесь от этой черты характера. Некрасиво это.


                                                                                                                                        От интеропа с джавой кровь идёт из глаз.

                                                                                                                                        Это справедливое замечание. Равно и про компаньоны. Равно как и про type erasure.


                                                                                                                                        А как вам такое: в Kotlin нет checked exceptions.

                                                                                                                                        И в C# нет. И в C++ нет. И много где ещё их нет, потому что checked exceptions — это как раз та бессмысленная часть, которая и делает Java многословной без веских на то оснований. В большинстве реальных случаев вам, признайтесь, по барабану список исключений, которые выбрасывает метод. У вас или все ошибки обрабатываются одинаково, или же вы предпочтёте выбрать пару исключений, которые обрабатываются как-то иначе (а все остальные — всё равно одинаково). Тащить за собой список исключений в этой ситуации не имеет никакого смысла. Практической пользы от него — 0.


                                                                                                                                        Автоматические геттеры/сеттеры

                                                                                                                                        Господи, ну наконец-то хоть у одного JVM-языка появилась эта функциональность. Наконец-то на JVM-языке (вкупе с перегрузками) можно писать point2.Z = (point1.X + point1.Y)*(point2.X - point2.Z), а не point2.setZ(Point.mult(Point.sum((point1.getX(), point2.getX())),Point.subtr(point2.getX(), point2.getZ()))). Да здравствует человеческая инфиксная запись! Ура, товарищи! К 2018 году JVM-язык научился делать то, что человечество использует уже несколько веков.


                                                                                                                                        Экстеншн-методы

                                                                                                                                        Читайте что такое примеси и будете вознаграждены. Не надо критиковать то, чего не понимаете — вас на смех поднимут. Тем временем, примеси — мощнейший механизм, который позволяет делать шедевральной компактности и выразительности код. Немного терпения в освоении и вам откроется истина. Шарписты гарантируют.


                                                                                                                                        reduce и fold

                                                                                                                                        Эм… Вообще-то они так работают во всех языках, в которых они есть. В C# вот reduce-а в явном виде нет. Но его легко можно написать. И когда вы это сделаете — вы поймёте почему reduce на пустой коллекции должен бросать исключение.


                                                                                                                                        Нафига в стандартную библиотеку языка, который поддерживает дата-классы, включили пары?

                                                                                                                                        Чтобы вы не захламляли код коммерческого приложения своего работодателя отрядами классов из двух пропертей/полей. Знаете, если вы работаете в команде лоботрясов, то один лоботряс сделает свой Pair для использования в паре мест, второй сделает такой же, третий… И вот у вас уже 10 разных Pair-ов с разными типами и именами, в разных пакетах от разных лоботрясов. Чтобы этой фигни не происходило, люди придумали встроенные в язык туплы (а заодно и деконструкцию классов, просто потому что могут).
                                                                                                                                        Если же вас тянет использовать туплы чтобы заменить ими ВООБЩЕ ВСЁ — вы больны. Не надо проецировать свою болезнь на других. Специально чтобы технически оградить психически нестабильных персоналиев от подобной ереси, встроенные туплы обычно ограничивают 4-8 тип-аргументами. Если вам нужно больше — обычно это говорит о том, что надо делать отдельный промежуточный класс (дата или не дата — это уже вам решать).


                                                                                                                                        Очень странный момент — возможность не указывать возвращаемый тип метода

                                                                                                                                        Очередной привет людям, которые пугаются type inference-а. Идите к группе людей вон там в углу, которые не понимают зачем нужен var. И предложите им оперировать хэшмапой тупл-> список generic-интерфейсов без var и с явным указанием результата работы метода. Ах, вы такого в жизни никогда не писали? Так может имеет смысл чуть по-дольше поработать в индустрии прежде чем критиковать?


                                                                                                                                        Для публичных методов явная спецификация API должна быть

                                                                                                                                        Она и есть. Метод возвращает kotlin.Any. Это очевидно компилятору, очевидно пользователям kotlin, очевидно пользователям библиотек с такими заковырками. Всем, кроме вас.


                                                                                                                                        В общем, автор. Ничего личного, но поднимайте, пожалуйста, квалификацию.

                                                                                                                                          +2
                                                                                                                                          В C# вот fold-а нет

                                                                                                                                          Есть. Он называется Aggregate.
                                                                                                                                          double product = doubles.Aggregate(1.0, (prod, next) => prod * next);
                                                                                                                                            +1

                                                                                                                                            Это reduce в терминологии автора

                                                                                                                                              +1

                                                                                                                                              Нет, reduce — это вот этот:


                                                                                                                                              double product = doubles.Aggregate((prod, next) => prod * next);

                                                                                                                                              И это не терминология автора, а функции из стандартной библиотеки Kotlin: fold, reduce

                                                                                                                                                +2

                                                                                                                                                А, значит я их местами перепутал.

                                                                                                                                            +1
                                                                                                                                            Она и есть. Метод возвращает kotlin.Any.

                                                                                                                                            Ну уж нет! Метод с автоматически выведенным типом результата возвращает этот самый автоматически выведенный тип, но никак не kotlin.Any.

                                                                                                                                              +2

                                                                                                                                              Нене. Я подозреваю что там type inferer ищет максимально общего предка для всех возможнных return-значений. Если, как автор в своём примере, мы подпихиваем совершенно несовместимые типы, то в результате разумно предположить что будет kotlin.Any. То есть это было сказано про данный конкретный случай, а не вообще. Хотя надо пощупать это поведение.
                                                                                                                                              Иными словами, kotlin не запрещает стрелять себе в ногу. И это правильно.

                                                                                                                                              0
                                                                                                                                              Ох уж эти проклятые геттеры/сеттеры, спать не дают))
                                                                                                                                                      //java
                                                                                                                                                      int sum = point1.getX() + point1.getY();
                                                                                                                                                      int subtr = point2.getX() - point2.getZ();
                                                                                                                                                      point2.setZ(sum * subtr);
                                                                                                                                              
                                                                                                                                                      //kotlin
                                                                                                                                                      var sum = point1.x + point1.y;
                                                                                                                                                      var subtr = point2.x - point2.z;
                                                                                                                                                      point2.z = sum * subtr;
                                                                                                                                              
                                                                                                                                                +2
                                                                                                                                                //Java
                                                                                                                                                point2.setZ((point1.getX() + point1.getY()) * (point2.getX() - point2.getZ()));
                                                                                                                                                
                                                                                                                                                //Kotlin
                                                                                                                                                point2.z = (point1.x + point1.y) * (point2.x - point2.z)

                                                                                                                                                Если вам нужны локальные переменные только для упрощения чтения кода — это уже о чём-то да говорит.
                                                                                                                                                Если они нужны где-то ещё далее по коду, то пусть будут конечно. Только в Kotlin рекомендуется использовать val.

                                                                                                                                                  +1

                                                                                                                                                  Ребят, обратите внимание что мой пример — он демонстрирует акцессоры вкупе с перегруженными операторами. X/Y/Z в общем случае могут быть не числами.