Наша команда, аналогично с автором статьи, уже почти как год перешла со Scala на Kotlin в качестве основного языка. Мое мнение во многом совпадает с автором, поэтому предлагаю вам перевод его интересной статьи.


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


Ниже я хочу привести примеры, которые мне нравятся в Scala и Kotlin, а также их сравнение в том, как они реализованы в обоих языках.


Объявление и выведение типов


Что мне особенно нравится в обоих языках так это то, что они оба являются статически типизированными с выведением типов. Это предоставляет вам возможность в полной степени воспользоваться мощью статической типизации без громоздких объявлений в коде (ориг.: declarative boiler plate). В большинстве случаев это работает в обоих языках. В обоих языках также прослеживается предпочтение неизменяемым типам вместе с опциональным объявлением типа переменной после ее названия.


Пример кода будет одинаковый в обоих языках:


Объявление неизменяемой переменной с именем age и типом Int:


val age = 1 

Объявление изменяемой переменной с типом String:


var greeting = "Hello"

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


Scala


val double = (i: Int) => { i * 2 }

Kotlin


val double = {i: Int -> i * 2 }

Data / Case классы


Scala и Kotlin имеют схожий концепт data классов, которые являются представлением data model object.


Подход в Scala

В Scala это case классы, которые выглядят следующим образом:


case class Person(name: String, age: Int)

  • Есть apply метод (не нужно использовать ключевое слово new при создание инстанса)
  • Методы для доступа объявлены для каждого property (если property объявлено как var то setter метод также будет присутствовать)
  • toString, equal и hashCode разумно объявлены
  • Eсть copy функция
  • Есть unapply метод (который позволяет использовать данные классы в pattern matching)

Подход в Kotlin

Kotlin называет данные классы как data class


data class Person (val name: String, val age: Int)

Ключевые особенности:


  • Методы для доступа объявлены для каждого property (если property объявлено как var то setter метод также будет присутствовать). Это не исключительная особенность data классов, утверждение справедливо для любых классов в Kotlin.
  • Разумно объявлены toString, equal и hashCode
  • Сopy функция
  • component1..componentN функции. По аналогии используется в качестве unapply.
  • Реализует JavaBean getter и setter, необходимых для таких Java фреймворков как Hibernate, Jackson, без изменений.

В Kotlin нет необходимости в специальном apply методе, также как и не нужно ключевое слово new для инициализации класса. Так что это стандартное объявление конструктора как и для любых других классов.


Сравнение


В основном case и data классы похожи.


Пример ниже выглядит одинаково в обоих языках:


val jack = Person("jack", 1)
val olderJack = jack.copy(age = 2)

В целом я нашел data и case классы взаимозаменяемым в повседневном использовании. В Kotlin есть некоторые ограничения на наследование data классов, но это было сделано из благих намерений c учетом реализации equals и componentN функций, чтобы избежать подводных камней.


В Scala case классы более мощные в pattern matсhing по сравнению с тем как Kotlin работает с data классами в ‘when’ блоках, в которых этого не хватает.


Подход Kotlin работает лучше для существующих Java фреймворков, т.к. они выгдядят для них как обычные Java bean.


Оба языка позволяют передавать параметры по имени и позволяют указать значению по умолчанию для них.


Null Safely / Optionality


Подход в Scala

В Scala null safely заключается в использовании монады option. Проще говоря, option может находится в одном из двух конкретных состояний: Some(x) или None


val anOptionInt: Option[Int] = Some(1)

или


val anOptionInt: Option[Int] = None

Можно оперировать с option при помощи функций isDefined и getOrElse (чтобы указать значение по умолчанию) но более часто используемая ситуация когда монады используется с операторами map, foreach или fold, для которых option представляет из себя коллекцию содержащую 0 или 1 элемент.


Для примера можно подсчитать сумму двух опциональных переменных следующим образом:


val n1Option: Option[Int] = Some(1)
val n2Option: Option[Int] = Some(2)
val sum = for (n1 <- n1Option; n2 <- n2Option) yield {n1 + n2 }

В Переменной sum будет значение Some(3). Наглядный пример того как for может быть использован как foreach или flatMap в зависимости от использования ключевого слова yield.


Другой пример:


case class Person(name: String, age: Option[Int])
val person: Option[Person] = Some(Person("Jack", Some(1)))
for (p <- person; age <- p.age)  {
   println(s"The person is age $age")
}

Будет напечатана строчка "The person is age 1"


Подход в Kotlin

Kotlin заимствует синтаксис groovy, достаточно практичный в повседневном использовании. В Kotlin все типы non-nullable и должны быть в явном виде объявлены nullable с помощью "?" если они могут содержать null.


Тот же пример может быть переписан следующим образом:


val n1: Int? = 1
val n2: Int? = 2
val sum = if (n1 != null && n2 != null) n1 + n2 else null

Это намного ближе к Java синтаксису за исключением того, что Kotlin принудительно выполняет проверки во время компиляции, запрещая использовать nullable переменные без проверки на null, так что можно не бояться NullPointerException. Также нельзя присвоить null переменной объявленной как non-nullable. Помимо всего компилятор достаточно умный, чтобы избавить от повторной проверки переменной на null, что позволяет избежать многократной проверки переменных как в Java.


Эквивалентный Kotlin код для второго примера будет выглядеть следующим образом:


data class Person(val name: String, val age: Int?)
val person: Person? = Person("Jack", 1)
if (person?.age != null) {
  printn("The person is age ${person?.age}")
}

Или альтернативный вариант с использованием "let", который заменает "if" блок на:


person?.age?.let {
  person("The person is age $it")
}

Сравнение


Я предпочитаю подход в Kotlin. Он гораздо более читабельный и понятный, и проще разобраться что происходит в многократных вложенных уровнях. Подход Scala отталкивается от поведения монад, который конечно нравится некоторым людям, но по собственному опыту могу сказать, что код становится излишне перегруженным уже для небольших вложений. Существует огромное количество подводных камней у подобного усложнения в использовании map или flatMap, причем вы даже не получите предупреждение при компиляции, если вы делаете что-то не так в мешанине из монад или используя pattern match без поиска альтернативных вариантов, что в результате выливается в runtime exception которые не очевидны.


Подход в Kotlin также уменьшает разрыв при интеграции с кодом Java благодаря тому что типы из нее по умолчанию nullable (тут автор не совсем корректен. Типы из Java попадают в промежуточное состояние между nullable и not-nullable, которое в будущем можно уточнить), тогда как Scala приходится поддерживать null как концепт без null-safely защиты.


Функциональные коллекции


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


В примере ниже нет особых различий в работе fold и map функций:


Scala


val numbers = 1 to 10
val doubles = numbers.map { _ * 2 }
val sumOfSquares = doubles.fold(0) { _ + _ }

Kotlin


val numbers = 1..10
val doubles = numbers.map { it * 2 }
val sumOfSquares = doubles.fold(0) {x,y -> x+y }

Оба языка поддерживают концепт цепочки "ленивых" вычислений. Для примера вывод 10 четных чисел будет выглядеть следующим образом:


Scala


val numbers = Stream.from(1)
val squares = numbers.map { x => x * x }
val evenSquares = squares.filter { _%2 == 0 }
println(evenSquares.take(10).toList)

Kotlin


val numbers = sequence(1) { it + 1 }
val squares = numbers.map { it * it }
val evenSquares = squares.filter { it%2 == 0 }
println(evenSquares.take(10).toList())

Implicit преобразования vs extension методы


Эта та область в которой Scala и Kotlin немного расходятся.


Подход в Scala

В Scala есть концепция implicit преобразований, которая позволяет добавлять расширенный функционал для класса благодаря автоматическому преобразованию к другому классу при необходимости. Пример объявления:


object Helpers {
  implicit class IntWithTimes(x: Int) {
    def times[A](f: => A): Unit = {
       for(i <- 1 to x) {   
         f 
       }
    }
  }
}

Потом в коде можно будет использовать следующим образом :


import Helpers._
5.times(println("Hello"))

Это выведет "Hello" 5 раз. Работает это благодаря тому, что при вызове функции "times" (которая на самом деле не существует в Int) происходит автоматическая упаковка переменной в объект IntWithTimes, в котором и происходит вызов функции.


Подход в Kotlin

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


fun Int.times(f: ()-> Unit) {
  for (i in 1..this) {
    f()
  }
}

5.times { println("Hello")}

Сравнение


Подход Kotlin соответствует тому как я в основном использую данную возможность в Scala, с небольшим преимуществом в виде чуть более упрощенной и понятной записи.


Особенности Scala которых нет в Kotlin и по которым я не буду скучать


Одна из лучших особенностей Kotlin для меня даже не в том функционале что есть, а больше в том функционале которого нет в Kotlin из Scala.


  • Вызов по имени — Это разрушает читабельность. Если функция передается было бы гораздо легче увидеть что передается указатель на функции при простом просмотре кода. Я не вижу никаких преимуществ, которое это дает по сравнению с явной передачей лямбд.
  • Implicit преобразования — Это то что я действительно ненавижу. Это приводит к ситуации, когда поведение кода значительно меняется в зависимости от того, что было импортировано. В результате действительно тяжело сказать какая переменная будет передана в функцию без хорошей поддержки IDE.
  • Перегруженный for — Проблема с несколькими монадами, показанная выше.
  • Беспорядок с опциональным синтаксисом infix и postfix операторов — Kotlin чуть более формализованный. В результате код в нем менее двухсмысленный,  его проще читать и не так легко простой опечатке стать неочевидной ошибкой.
  • Переопределением операторов по максимуму — Kotlin разрешает переопределение только основных операторов (+, — и т.п.). Scala разрешает использовать любую последовательности символов. Действительно ли мне нужно знать разницу между "~%#>" и "~+#>"?
  • Медленное время компиляции.

Спасибо за внимание.
Оригинал Scala vs Kotlin
P.S. В некоторые местах в переводе специально оставил слова без перевода (null, null safely, infix, postfix и т.п.).

Поделиться с друзьями
-->

Комментарии (124)


  1. seryh
    26.08.2016 12:49
    +1

    Если нет аллергии на динамическую типизацию, то можно было еще рассмотреть соседа по JVM — clojure. Например ленивое получение 10 четных чисел, на Clojure выглядит так:
    (->> (range) (filter even?) (take 10))


    1. UbuRus
      26.08.2016 13:13
      +2

      Это действительно очень нужный и полезный код. Как правило мы не считаем последовательности Фибоначчи и не генерируем четные числа.


      1. seryh
        26.08.2016 13:18
        +1

        Я за вас несомненно рад, но этот же пример есть в самой статье. Не могли бы вы адресовать ваше негодование автору?


        1. UbuRus
          26.08.2016 13:25
          +2

          В статье все-таки немного другой код и только для сравнения синтаксиса языков.

          Ну и для примера аналогичный Clojure код на Kotlin

          (->> (range) (filter even?) (take 10))
          range.asSequence().filter { it % 2 == 0 }.take(10)
          


          В чем преимущество? Преимущество Kotlin в том, что любой Java разработчик поймет Kotlin вариант, а вот поймет ли он семантику и синтаксис Clojure варианта?


          1. seryh
            26.08.2016 14:25

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


            1. UbuRus
              26.08.2016 14:39
              +3

              По синтаксису вижу в обоих вариантах — английский


              Хорошая шутка, я все же говорил что у Clojure Schema подобный синтаксис, а вот Kotlin — С подобный.


  1. lany
    26.08.2016 12:55
    +11

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


    1. nerumb
      26.08.2016 12:59
      +4

      По своему опыту могу сказать что критичных багов мы тоже не нашли. Есть некоторые вещи, которых сильно не хватает, например typedef. Но в версии 1.1. они появятся.


    1. TheKnight
      26.08.2016 13:10
      +1

      А можно более подробно про баги компилятора и недоработки в стандартной библиотеке? Ну и да — это были баги и недоработки уже после релиза?


      1. leventov
        28.08.2016 22:45

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


      1. Throwable
        29.08.2016 13:09
        +1

        Неделю назад нужно было написать простой парсер логов одного приложения, ничего особенного. Попробовал Котлин. В итоге: Regex matcher не работает, а File.forEachLine мистически виснет. Заменил все джавовскими аналогами Pattern.compile/Matcher и BufferedReader. Фигня конечно, но как-то стремно, ибо чревато на ровном месте геморроем.


        1. nerumb
          29.08.2016 13:53

          Regex matcher не работает, а File.forEachLine мистически виснет.

          Можете привести примеры кода?


          1. Throwable
            29.08.2016 17:20
            +2

            val MSG = "Async service invocation: ISigresPartner Interface=INT.SIGRES.PSSBA.001 #_PI:90030156.2de27eff.e6df58f5.71524441"
            // Java Regexp
            val invokeMatcher = Pattern.compile(
                    """.*:\s+([A-Za-z0-9\._-]+)\s+Interface=([A-Za-z0-9\._\-]+).+#(.+)""")
            val match = invokeMatcher.matcher(MSG)
            println(match.find())
            // -> true
            // Kotlin
            println(Regex.fromLiteral(""".*:\s+([A-Za-z0-9\._-]+)\s+Interface=([A-Za-z0-9\._-]+).+#(.+)""").matches(MSG))
            // -> false
            println(Regex.fromLiteral(""".*:\s+([A-Za-z0-9\._-]+)\s+Interface=([A-Za-z0-9\._-]+).+#(.+)""").find(MSG))
            // -> null

            Regex 100% правильный, можете проверить на regex101.com.


                val files = File(logDir).listFiles {
                    dif, name -> name.startsWith("SystemOut") && name.endsWith(".log")
                }.asList().sortedBy { if (it.name == "SystemOut.log") "Z" else it.name }
            
                files.forEach { file ->
                    file.forEachLine { line ->
                        // ...
                    }
                }
            
            Зависает. Но не на процессинге линии, а на чтении.


            1. lany
              29.08.2016 21:23
              +1

              С регексом вы прокосячили. Вам нужно просто Regex(...), а не Regex.fromLiteral(...). Может, конечно, хелп мутно написан, но fromLiteral — это regex-литерал, просто точное совпадение с заданной строкой (как и Pattern.LITERAL в Java).


            1. nerumb
              30.08.2016 08:55

              1) На счет regex вам уже ответили.

              2) По поводу зависания.
              Попробовал аналогичный код, у меня все работает. forEachLine по сути перебирает Sequence из BufferedReader:

              public fun File.forEachLine(charset: Charset = Charsets.UTF_8, action: (line: String) -> Unit): Unit {
                  // Note: close is called at forEachLine
                  BufferedReader(InputStreamReader(FileInputStream(this), charset)).forEachLine(action)
              }
              

              public fun Reader.forEachLine(action: (String) -> Unit): Unit = useLines { it.forEach(action) }
              

              public inline fun <T> Reader.useLines(block: (Sequence<String>) -> T): T =
                      buffered().use { block(it.lineSequence()) }
              

              public inline fun Reader.buffered(bufferSize: Int = DEFAULT_BUFFER_SIZE): BufferedReader
                      = if (this is BufferedReader) this else BufferedReader(this, bufferSize)
              

              public inline fun <T> Sequence<T>.forEach(action: (T) -> Unit): Unit {
                  for (element in this) action(element)
              }
              

              public fun BufferedReader.lineSequence(): Sequence<String> = LinesSequence(this).constrainOnce()
              

              Думаю что у вас проблема не в Kotlin, а в чем-то другом.


              1. Throwable
                30.08.2016 13:19

                1) Да, мой косяк. Но почему-то в обоих случаях Regex.toString() возвращает одну и ту же строку.
                2) Возможно. Я сильно не разбирался — не было времени. Парсилось около 50 файлов по 10Мб каждый. Зависание происходило спонтанно, каждый раз в новом месте, иногда даже прокатывало без зависаний. Но тред именно в read-е сидел. Странно.


                1. lany
                  30.08.2016 13:44

                  1) Ну строка одна, но флаги разные. Regex в Java — это строка плюс флаги. Котлиновский регекс — просто обёртка над джавовским.


    1. molchanoviv
      26.08.2016 13:24
      +2

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


    1. lookid
      26.08.2016 20:53
      +1

      Советую посмотреть доклад Антона Кекса «Anton Keks — Kotlin in real projects: pragmatic opinion on pragmatic language (Ru)»


  1. cs0ip
    26.08.2016 13:04
    +3

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


    1. nerumb
      26.08.2016 13:09
      +2

      Сам язык появился не год назад, а гораздо раньше.


      1. cs0ip
        26.08.2016 13:11
        +4

        Но использовать его в продакшене до первой стабильной версии никто бы не стал, поэтому имеет смысл говорить именно об этой дате.


        1. nerumb
          26.08.2016 13:36
          +1

          Кстати интересно, а вы пробовали написать что-нибудь на Kotlin? Особенно в совокупности с gradle?


          1. cs0ip
            26.08.2016 13:55
            +1

            Я всё жду статью, которая объяснит мне, зачем это делать. Пока лишь вижу какую-то субъективщину и вкусовщину. К тому же ряд возможностей scala, которые некоторые пытаются занести в недостатки, мне нравятся и их будет не хватать. Тот же implicit можно использовать безопасно и удобно в куче сценариев. А без pattern matching'а вообще не понятно как писать компактный код, это ж java какая-то получается.


            1. nerumb
              26.08.2016 14:13
              +1

              А без pattern matching'а вообще не понятно как писать компактный код, это ж java какая-то получается.

              when в Kotlin это switch на стероидах. Он, конечно, полноценно не может заменить pattern matching, но с ним можно жить.
              Ниже несколько примеров:
              when(obj) {
               is String -> // matches on the type
               parseInt(obj) -> // invoked method parseInt
               else -> // otherwise
              }
              

              when {
               person.name == "bobby" ->
               x.isOdd() ->
               else ->
              }
              

              Также чуть позже должна появиться возможность использовать «Destructuring Declarations» в when, тогда станет еще проще.

              Но то что полноценный pattern matching нужен, тут я с вами согласен. Но это пожалуй единственная вещь который не хватает в Kotlin. И совокупное впечатление от языка только положительное.


            1. bean
              26.08.2016 15:17
              +1

              Вряд ли какая-то статья даст вам конкретный ответ на этот вопрос, пока сами не попробуете.

              В сравнение со скалой, вероятно, переходить особого смысла и нет. Хотя если говорить еще про отличия и плюсы, то в статье не упомянули про инлайн функций и reified type parameters. На скале такое сделать значительно трудней. Очень радует маленький рантайм самого языка, особенно это удобно на андроиде, на скале с этим пока не так весело, но работы там вроде как ведутся. Еще в котлине заморочились c примитивами и их массивами, массивы также поддерживают все операции работы с коллекциями (map, find...), причем реализованы они не через ссылочные типы, т.е. боксинга/анбокисинга не будет, если конечно результат потом как-то не явно будет приведен к ссылочному типу, например, объявлен как nullable.

              Из минусов:
              — плагин для идеи периодически крашится, не критично, но хочется чтобы его довели до уровня;
              — странный синтаксис в некоторых местах, например при объявлении свойств и если вдруг захочется добавить аннотацию к конструктору, то придется явно это указать;


              1. Googolplex
                27.08.2016 13:11
                +1

                инлайн функций и reified type parameters. На скале такое сделать значительно трудней

                Здесь я оставлю ссылку на проект SIPа который делает именно это и даже круче. Есть шанс, что в каком-то виде в новых версиях скалы это появится.


              1. nerumb
                29.08.2016 15:33

                то в статье не упомянули про инлайн функций и reified type parameters

                inline все же в scala есть считай из «коробки», а вместо reified type есть TypeTag (если не путаю) с большим функционалом.

                Основное преимущество Kotlin в его времени компиляции (в теории можно довести до уровня Java), интеропе с Java (нет отдельного мира с коллекциями как в Scala) и удобном наборе возможностей языка, достаточным для продуктивной работы. Тот же DSL на extension функциях/параметрах можно сделать очень даже просто.


                1. bean
                  29.08.2016 15:46
                  +1

                  inline все же в scala есть считай из «коробки», а вместо reified type есть TypeTag (если не путаю) с большим функционалом.

                  Все же разница там есть, если вы говорите про аннотацию inline, то мне кажется текущая версия комплятора скалы не сможет так развернуть лямбды, как это делает котлин, например, для всех функций работы с коллекциями. Если же речь о макросах, то тут у скалы возможности не ограничены, но использовать их сложней. reified type parameters связаны как раз именно с инлайном, поэтому у скалы вероятно тут прямого аналога нет, а TypeTag это вообще вроде как фича из рефлекшена, разве нет?

                  А так полностью согласен.


                  1. nerumb
                    29.08.2016 16:05

                    reified type parameters связаны как раз именно с инлайном

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

                    TypeTag это вообще вроде как фича из рефлекшена

                    Из рефлекшена, но в итоге TypeTag в Scala позволяет «прокидывать» информацию о типе в рантайм. Reified type в Kotlin делает примерно тоже самое.


      1. molnij
        26.08.2016 13:14

        вы его начали использовать до релиза?


        1. nerumb
          26.08.2016 13:18
          +1

          Чуть раньше, начиная с беты начали делать на нем небольшие компоненты и небольшой проект.


  1. Saffron
    26.08.2016 13:16
    +1

    > Implicit преобразования — Это то что я действительно ненавижу. Это приводит к ситуации, когда поведение кода значительно меняется в зависимости от того, что было импортировано.

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

    Кстати, без implicit не было бы замечательной библиотеки коллекций скалы. СanBuildFrom работает на импилиситах.

    А ешё вы не упомянули скаловскую фичу View Bound, без которой достаточно кисло в некоторых случаях, когда хочется типобезопасно выразить полиморфизм. И она тоже работает через implicit.

    > Проблема с несколькими монадами, показанная выше.

    Вы видимо забыли перенести кусок кода из черновика, никаких проблем монад не описано — только использование.

    > Действительно ли мне нужно знать разницу между "~%#>" и "~+#>"?

    Задайте этот вопрос автору библиотеки, а не языка.

    Ну и самое интересное вы не рассказали — как вам понравились в сравнении скаловский и котлиновский pattern matching.


    1. nerumb
      26.08.2016 13:22
      +1

      то есть DI вы тоже предпочитаете избегать, потому что поведение кода начинает зависеть от xml файла конфигурации.

      В статье приведено мнение автора, но да, мне тоже не нравится implicit. Но никто про DI не говорит что его нужно избегать (правда без xml конфигурации).

      Вы видимо забыли перенести кусок кода из черновика, никаких проблем монад не описано — только использование.

      Тут вопрос к автору

      Ну и самое интересное вы не рассказали — как вам понравились в сравнении скаловский и котлиновский pattern matching

      автор как раз и говорит что ему не хватает pattern matching в kotlin


    1. cs0ip
      26.08.2016 13:30

      Всё-таки не view bounds (которые устарели), а context bounds.


    1. ppopoff
      26.08.2016 15:20

      А ешё вы не упомянули скаловскую фичу View Bound, без которой достаточно кисло в некоторых случаях, когда хочется типобезопасно выразить полиморфизм. И она тоже работает через implicit.

      их уже поместили в deprecated. Так что scala скоро останется без них.


  1. nerumb
    26.08.2016 13:17

    deleted


  1. mukeb
    26.08.2016 15:53
    +2

    Преимущество implicit conversion против extension methods в том что implicit converion-ы хорошо расширяются, что не скажешь о extension methods. В скала вообще расширяется все что только можно (само название языка об этом говорит).


    1. nerumb
      26.08.2016 15:54
      +1

      Но extension методы более понятны и читабельны. Для более сложных вещей есть другие подходы.


  1. ppopoff
    26.08.2016 16:33
    +11

    Люди сравнивают синтиаксис: Вот тут у меня def, а тут у меня fun… А вот смотрите я тут пишу фигурные скобочки а тут могу не писать. А еще тут у меня есть сахарок. Кому-то не нравятся угловые скобки в котлине потому-что они отдают джавой. "Ой, а вот я не знаю что лучше it в груви, или нижнее подчеркивание в scala", — произносит молоденькая девочка поправляя очки. Смотрю я на подобные статьи и умиляюсь, ибо люди которые их пишут не понимают главного: Синтаксис вторичен. Я, кстати ожидал увидеть сравнение HelloWorld программ. Рад что хотя бы этого здесь нет
    Еще раз, я не говорю что синтакс не важен, я говорю что он вторичен.
    Если вы выбираете язык исключительно потому что вам нравится синтаксис/сахарки. Вы недостаточно взрослый инженер чтобы принимать решения архитектурного уровня. Я видел инжинеров принмавших следующее решение: "Языком для нашей команды будет scala потому что у ней есть var и val". Знаете где сейчас этот инженер? Он живет себе спокойненько и пишет на Java. Потому что в скале разочаровался. Сложная она ему.


    Язык это инструмент который позволяет решать задачи, для кого-то бизнес-задачи. И требования которые предъявляются к языку? Как он эти задачи решает верно? Поэтому первым пунктом рассматриваются библиотеки доступные для языка, потом рассматривается сама платформа, как она работает, где проседает по производительности и тд. Это требование называется "экосистемой". В случае с java, kotlin и scala, спорить бесмысленно, хотя… нам тут обещают scala.native, scala.js (у котлина тоже есть возможность собираться в js). Почему бы при сравнении не обыграть этот факт? наличие возможности собираться в нативный код может стать судьбоносным при выборе языка программирования.
    Потом идут возможности языка/платформы. Почему бы не сравнить работу рефлексии в scala/kotlin. А есть ли в котлине макросы? А как они работают? В Scala второе поколение макро решений сменяется.


    Одна из лучших особенностей Kotlin для меня даже не в том функционале что есть, а больше в том функционале которого нет в Kotlin из Scala.

    Вот собственно то что должно было быть в статье про kotlin и scala. А именно, мощь, средства выразительности языка которые скрываются за синтаксом.
    Ну что, пройдемся по списку написанного автором? Поехали


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

    Call-by-name это вообще стратегия вычисления (evaluation strategy). Тут о читаемости вообще никакой речи не идет. Это мощь в чистом виде. И это та мощь которая лежит за синтаксом.


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

    Вы хотите особого вида операторы для Float, как в Ocaml? В скале это не только преобразования :). Есть например implicit parameters. Которые могут красиво просовываться туда где для них есть место. Разве у вас не было случаев когда вам нужно было постоянно проносить некоторый контекст везде где только можно? Думаю что было. Есть implicit классы, которые реализуют extension методы. Функционал сопоставимый. Однако, я нахожу implicit классыы более абстрактным и выразительным средством. Есть еще одно выразительное средство, которого в Котлин (я могу ошибаться) точго нет. Знаете какое? Type classes (или ad-hoc полиморфизм). И тут, scala достает из кармашка свои имплиситы и вытряхивает их перед вами, а затем с их помощью позволяет реализовать классы типов. Вы пробовали классы типов когда-нибудь?). Попробуйте. Рекламировать их не буду.


    Перегруженный for — Проблема с несколькими монадами, показанная выше.
    Беспорядок с опциональным синтаксисом infix и postfix операторов — Kotlin чуть более формализованный. В результате код в нем менее двухсмысленный, его проще читать и не так легко простой опечатке стать неочевидной ошибкой.

    Про for, возможно соглашусь, а вот по поводу postfix операторов усомнюсь. Да, postfix синтаксис способен снести парсеру крышу. Опять таки postfix операторы создавались для возможности делать внятные DSL. DSL это один шаг к Language Oriented programming. За свое время я реализовывал несколько DSL для разных предметных областей. Тот выигрыш, который они дают в продуктивности описать трудно. Но он значительный.
    Опять таки, если вы хотите использовать фичи языка включите их:


      import scala.language.implicitConversions
      import scala.language.postfixOps

    Не хотите, не включайте. Смысл ругать язык за наличие более глубокой функциональности? Кто-то может воспользоваться? Следите за персоналом. Для других языков вполне нормальная пратика иметь codestyle, с которым знакомятся все разработчики когда попадают в команду. добавить туда 7 слов особой проблемы не составит: "не использовать имплиситы и постфиксные операторы".


    Ну, беспорядок с опциональным синтаксисом помоему как раз царит в котлине. У меня порой создается впечатление, что язык разрабатывался ради великой цели: обойти косяк платформы в виде NullPointerException. Конечно же NPE это проблема, и решение для нее вполне очевидно, использовать опшны. Да в том виде в каком они есть. Да синтаксис можно было бы для них взять котлиновский. Но оставить Optionами. Андрей Бреслав в одном своем докладе сказал что они не выбрали Option потому что это лишний объект в памяти. в JDK 9 нам обещают проевт valhala. Уверен что есть возможность сжульничать на этапе кодогенерации временно генерировать Option.None в null. Если таковой возможности нет, буду рад если меня кто-то просветит. Про Optionы скажу лишь одно: все мы там будем. Это будщее, это эволюция.


    Переопределением операторов по максимуму — Kotlin разрешает переопределение только основных операторов (+, — и т.п.). Scala разрешает использовать любую последовательности символов. Действительно ли мне нужно знать разницу между "~%#>" и "~+#>"?

    Да, порой перегрузка операторов (в некоторых библиотеках) она просто ужасна. Да, можно пойти по стопам C++, где >> обозначает не совсем очевидные вещи. А вы задавались вопросом для чего это сделано? Для построения DSL. Посмотрите например на Parboiled. Перегруженна вообще тильда. Как выглядит код? Как вполне себе BNF. А как выглядят роутинги в Spray? Этого всего бы не было если бы не перегрузка операторов. И да в том виде в каком она есть. А знаете ли вы что хорошей практикой считается дублировать символьные имена методов, текстовыми? Если такой возможжности нет, пинайте разработчиков библиотеки. Это они плохие люди, а не Мартин Одерски.


    Медленное время компиляции.

    Это как раз то что имеет значение. Тут котлин выигрывает и это действительно важно. Почему это идет в конце статьи я не понимаю.


    Да, я люблю scala. Она дает ту мощь, которую врядли даст какой-нибудь из известных языков. Ибо по сложности (как мне видится) она вполне себе переплевывает Haskell. Я хорошо отношусь к Kotlin. Да, я вижу его как обрезанную scala, и не вижу в этом ничего плохого. К сожалению, или к счастью, я считаю котлин более перспективным нежели scala.
    Конечно же, время покажет.


    Уважаемые хабравчане, пожалуйста, не сравнивайте языки по синтаксису. Победителем всегда будет LISP :)


    1. Lamaster
      26.08.2016 18:08
      +5

      > Победителем всегда будет LISP :)
      (Ага (Конечно))


    1. taujavarob
      26.08.2016 19:32
      -5

      пожалуйста, не сравнивайте языки по синтаксису.


      Это единственное по чём их можно и нужно сравнивать. Всё остальное развивается и прилагается (если требуется). Имхо.


      1. UbuRus
        26.08.2016 19:35
        +3

        Ну почему, можно еще сравнивать по типизации(groovy vs продакшен языки), наличии рантайма(Scala Native vs JVM), различным гарантиям (Kotlin с notnull типами vs другие языки под JVM) и т.д.


        1. taujavarob
          26.08.2016 19:54
          -3

          Ну почему, можно еще сравнивать по типизации(groovy vs продакшен языки), наличии рантайма(Scala Native vs JVM), различным гарантиям (Kotlin с notnull типами vs другие языки под JVM) и т.д.


          Всё это уже добавлено(или будет добавлено или будет убавлено) везде и всюду(где надо или не надо) и в конечном итоге всё это «компилируется» в JavaScript ES5


          1. UbuRus
            26.08.2016 20:05
            +1

            webassembly+es5 (javascript es5 — масло маслянное) же. Но суть не в этом, в Java notnull типы в обозримом будущем не впилят, Groovy так и останется скриптовым языком, и т.д. C++ не станет таким же безопасным как Rust, а в Go не добавят дженерики(citation needed). Scala/Clojure — это отдельный мир, Kotlin «паразитирует» на Java и это должно стать причиной его успеха.


            1. taujavarob
              26.08.2016 20:37

              webassembly+es5 (javascript es5 — масло маслянное) же


              Ну, JavaScript бывает и ES6 и ES7. На сегодня.

              Но суть не в этом, в Java notnull типы в обозримом будущем не впилят,

              Если бы 10 лет назад хоть кто-то знал что туда(Java) на сегодня уже впилили то! ;-)

              Уверен, в любой язык впилят то что будет модно (в тренде), вне наличия этого уже у другого языка.

              Пример ООП показывает — впилили куда только хотели.

              Аналогично впилят всюду (куда пожелают) и ФП.


              1. UbuRus
                26.08.2016 20:42
                +2

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


                1. taujavarob
                  26.08.2016 20:48
                  -1

                  Нельзя так просто впилить фичу в язык.

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

                  Да, пример (и длительность) впиливания лямбы в Java тому пример — но впилили же!

                  В любой язык можно впилить всё. В любой! Другое дело тренд, мода.
                  Я вот смотрю на исторические записи математиков — там они впиливали, например, интегральное и дифференциальное исчисление — каждый впиливал по своему, но в конце концов что-то выпилилось единое (не без скандалов).

                  В любой язык можно впилить всё. В любой! Другое дело тренд, мода. — и главное стилистика — эстетика языка. Именно поэтому Java в 1995 и взлетел — а не Паскаль или С++. Имхо.


      1. ppopoff
        26.08.2016 22:58

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


        Язык LISP знаменит своим синтаксисом, который основан на S-expressionах. Так вот. S-выражения изначально задумывались как… промежуточное представление. Изначально планировалось реализовать M-expressionы в качестве фасада. Потом уже S-выражения прижились. Синтаксис прилагается к ядру языка, а не наборот.


        1. taujavarob
          29.08.2016 17:04

          А давайте мы будем сравнивать дома по фасадам?


          Давайте. В своё время выбирали язык для реляционных баз данных — там «под капотом» было фактически одно и тоже.

          Выбрали «фасад» — SQL. — Причина выбора? — Выбрали специально такой язык чтобы им пользовались НЕ программисты — бухгалтера, экономисты, кладовщики, банковые служащие, чиновники и прочее.

          Выбор был сделал примерно из дюжины «фасада» языков (у всех «под капотом» реляционная алгебра) — Но вот кто использует сейчас SQL — это угадано при выборе НЕ было. Имхо.


          1. ppopoff
            29.08.2016 17:36

            Все что вы только что написали, доказывает вторичность синтаксиса. Дело в том что да, был язык который разрабатывался для того чтобы быть понятным для бухгалтеров, экономистов и кладовщиков. Появился этот язык в 1959 году и назывался далеко не SQL. И как показала практика, код на COBOL не программистами вообще не читался. Да это по прежнему был код, как бы читабельно он не выглядел. Более того. Существует ряд исследований касательно читаемости кода на COBOL, результаты которых не утешительны. Да, нормальные люди не в состоянии читать код, на каком бы языке он не был написан. И дело тут исключительно в людях, а не в языке. И где сейчас COBOL, c его предложениями, достойными Шекспира?


            А вот с SQL произошла другая история. Глубоко в недрах IBM, Э. Коддом разрабатывался язык, подкрепляющий теорию реляционных баз данных. Он был основан на исчислении кортежей, а так же на реляционной алгебре. Задачей языка было лечь на реляционную модель и служить средством ее описания (DDL), а так же выполнения манипуляций с данными (DML), а потом уже управление пользователями и их привелегиями (см DCL).


            Тот синтаксис, который мы видим сейчас в SQL, обязан лишь популярности COBOLа в момент своего создания (а это были семедисятые годы). И своей успешностью SQL, обязан исключительно своей семантике, но не синтаксису.


            К большому сожалению, сейчас SQL уже не отражает реляционную модель так как он это делал раньше (что например отмеченно в работе Дейта). Однако он по прежнему успешен, в виду того что стал стандартом де-факто для RDMS). Sql мог бы иметь и другой синтаксис. И это бы никак не повлияло на его успешность. К тому же для запросов выбран вполне себе функциональный подход. берем выборку фильтруем и трансформируем ее. Это уже простите не совсем синтаксис :)


            1. taujavarob
              29.08.2016 17:55

              Тот синтаксис, который мы видим сейчас в SQL, обязан лишь популярности COBOLа в момент своего создания (а это были семедисятые годы). И своей успешностью SQL, обязан исключительно своей семантике, но не синтаксису.


              Там фактически был отбор из дюжины языков.

              И выбор был сделан намеренный. В пользу SQL. Но в настоящее время мы видим — выбор был не угадан.

              Да, нормальные люди не в состоянии читать код, на каком бы языке он не был написан.

              Согласен. Но оставлены ли уже попытки создать такой язык?


              1. ppopoff
                30.08.2016 04:45

                Согласен. Но оставлены ли уже попытки создать такой язык?

                А смысл есть? Код могут воспринимать только люди способные алгоритмизировать. Это дано не всем. Маму научил решать элементарные задачи на питоне в ее 58 лет (аналог с поваренной книгой работает на ура). Приятелю 19 объясняю ему основы Pascal (который вижу более простым чем питон). Вроде бы все понимает, задачу алгоритмизировать не может. Так же не может восстановить ход мыслей. Делать языки "доступные" не-специалистам бессмысленно.


                Там фактически был отбор из дюжины языков.

                И выбор был сделан намеренный. В пользу SQL. Но в настоящее время мы видим — выбор был не угадан

                Ну а где сейчас прородитель то? Почил в бозе. Аналогичная ситуация была и с javascript если помните, который изначально был вполне себе scheme, но в виду маркетинговых соображений его переименовали из livescript (емнип) в javascript и добавили синтаксис отдаленно напоминающий Java. Кобол выбирали не потому что он понятный, а потому что в то время он был в тренде. Вы уверенны что точная причина именно псевдопонятность кобола? Я в этом глубоко сомневаюсь.


                1. taujavarob
                  30.08.2016 16:17
                  -1

                  А смысл есть? Код могут воспринимать только люди способные алгоритмизировать. Это дано не всем.

                  Дело в том. — Кому предназначен язык?

                  Ну, вначале то программирование в кодах. — Потом ассемблер — это для программистов.
                  Потом революция — язык C — простой, но для кого? — Для программистов.

                  Потом решили делать языки НЕ для программистов — Фортран (для физиков и инженеров), Кобол (для предприятий и экономистов).

                  Потом вспомнили опять про программистов:
                  Фортран + Кобол -> PL/1

                  Потом опять НЕ для программистов — SQL, dBase, Foxpro.
                  Потом — Clipper — фактически Foxpro для программистов с С-подобным синтаксисом.

                  Потом Java — отличная попытка сделать язык НЕ для студентов (Дельфи), а для программистов с С-шным синтаксисом но родным ООП (а не «нашлёпка ООП» над С (то есть не синтаксис С++)).

                  Аналогичная ситуация была и с javascript если помните, который изначально был вполне себе scheme, но в виду маркетинговых соображений его переименовали из livescript (емнип) в javascript и добавили синтаксис отдаленно напоминающий Java


                  Javascript — язык был явно предназначен для программистов (имхо). — Типа — когда Java-программист решит обратить внимание на броузер, ему будет хоть название ( и оператор new) знакомы! ;-)

                  Однако отвлечение программистов на java-апплеты тормознуло развитие Javascript. Но сейчас он решил взять реванш за все годы забвения! ;-)

                  Тогда вопрос — а для кого эти два языка — Scala и Kotlin ?


      1. firegurafiku
        27.08.2016 09:07
        +1

        Всё остальное развивается и прилагается (если требуется).

        Без поддержки на уровне синтаксиса многим из этого «всё остальное» будет просто невозможно нормально пользоваться, ну или, как минимум, предельно неудобное. Например, сравните удобство работы:


        • со строками в чистом C и C++ (где есть поддержка классов на уровне синтаксиса);
        • с традиционными ФП-шными map и filter в Lua (альтернативно: Python) и Haskell (где есть удобный синтаксис для лямбда-функций и срезов операторов);
        • с уже упомянутым Parboiled в Java и Scala (где есть кастомные и перегруженные операторы).

        Синтаксис очень важен, в отличие от вечных споров вида «фигурные скобки против begin—end».


        1. taujavarob
          29.08.2016 17:06

          Синтаксис очень важен, в отличие от вечных споров вида «фигурные скобки против begin—end».


          Так спор уже закончен. begin—end проиграли.


          1. ppopoff
            30.08.2016 04:45

            … есть такой язык, Ruby называется, его пользователи так не считают


            1. taujavarob
              30.08.2016 16:00

              есть такой язык, Ruby называется, его пользователи так не считают
              Хм. Забыл я про него. Каюсь.


    1. madhead
      26.08.2016 22:30
      +1

      Обещают с сентября начать работы над Kotlin Native.


      1. ppopoff
        26.08.2016 22:53

        Если обещают, было бы не плохо.


      1. senia
        26.08.2016 23:06
        +1

        Интересно посмотреть. Пока scala-native не часто используется — тут джетбрейновцы имеют хорошие шансы на лидерство.


        1. madhead
          26.08.2016 23:29

          Год ждать минимум. А то и больше.


        1. Saffron
          27.08.2016 03:56

          > тут джетбрейновцы имеют хорошие шансы на лидерство.

          Не верю. scala-native — это академический проект, и вряд ли джетбрейновцы добьются большего. Потому что kotlin-native, как и scala-native, требует как минимум java-native, а это такой вожделенный плод, что если бы его можно было достать, кто-нибудь из больших корпораций уже сорвал бы его.


          1. senia
            27.08.2016 08:17

            scala.sj продемонстрировал как можно обойтись без java-native. Правда тут у scala большое преимущество: огромное количество библиотек, написанных на scala (без java, кроме стандартной библиотеки), которые легко собрать под scala.js. Колтин же даже своей стандартной библиотеки не имеет.


            1. nerumb
              27.08.2016 09:06

              У Kotlin есть все тоже самое что написано для Java, и даже больше. Никто не мешает вам даже либы scala использовать


              1. senia
                27.08.2016 09:21
                +1

                Вы, кажется, выпали из обсуждаемого контекста. Тут речь исключительно про Kotlin Native и scala-native.
                По аналогии со scala.js: надо либо изобрести java-native (чтобы использовать java библиотеки из Kotlin Native), либо не использовать java библиотеки из Kotlin Native.
                Saffron высказал предположение, что первый путь затруднителен.
                В scala.js пошли по второму пути: там просто не используются java библиотеки, за исключением портированой части стандартной библиотеки. Котлин же себе такого позволить не может: он гораздо сильнее зависит от java окружения, чем scala.


            1. Saffron
              27.08.2016 11:36
              +1

              Чисто на скале, без задействования мощи JVM и рефлекшна, пишут по большей части ФП-фрики, радикальное крыло скалы программистов, всё на свете выражающее через типоклассы, о которых так нелестно отзывался автор статьи. Так что в натив или яваскрипт идёт не та скала, которая better java, а та скала, которая убогое подобие хаскеля и ML.

              Скомпилировать некоторое подмножество языка явы — посильный труд, о чём свидетельствует GCJ (GNU Compiler for Java). Но рантайм туда не входит, большинство библиотек отваливается, их надо переписывать. А ява знаменита именно количеством библиотек на все случаи жизни. Ява без библиотек не нужна — GCJ сдох. Кстати, его разработчики так и не успели даже стандартную библиотеку явы переписать.


            1. madhead
              27.08.2016 14:07

              Вообще-то имеет небольшую стандартную библиотечку. А ещё есть хоть какой-то бекенд под JS, который, скорее всего, не использует Java-библиотеку.


              Но это не основная проблема. Как сказано выше, основная проблема — нельзя будет использовать привычные библиотеки. Теряется весь смысл писать на Java / Scala / Kotlin. Проще будет взять C / С++. Возможно, с выходом Java 9 нативный компилятор "научится" понимать базовые модули, типа java.base, но даже это не шибко поможет.


          1. vsb
            27.08.2016 11:55
            +1

            Есть Kotlin для JavaScript, как вы понимаете, там никакого порта Java никто не делал. Всё, что котлин имеет общего — крошечная общая стандартная библиотечка. Её реализовать для Native реально.

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


      1. lany
        27.08.2016 16:23

        Насколько я понял из публичных высказываний на JetBrains Night, kotlin-native планируется как нишевой продукт для малых девайсов, IoT и т. д. В этом плане там, естественно, будет ограниченная библиотека.


        На десктопе есть компилируемая джава — Excelsior JET. Думаю, она и Котлин жрёт, она ж сертифицированная JVM. Полезная штука именно для десктопных приложений.


  1. aibar
    26.08.2016 19:32
    +1

    Минус scala только в его сложности и избыточности для «среднестатистического» программиста и для не слаженной команды любой масти. Для «топ» программиста или слаженной команды из «топ» программистов сплошные плюсы, и kotlin, ceylon или еще какие-то недоскала альтернативы не нужны.


    1. taujavarob
      26.08.2016 19:34
      -2

      Минус scala только в его сложности и избыточности для «среднестатистического» программиста и для не слаженной команды любой масти.


      Вот поэтому он и не взлетает.


    1. solver
      26.08.2016 23:19
      +3

      Это распространенное заблуждение. Очень жаль, что его культивируют.
      Большой плюс Scala как раз в том, что для продвинутых разработчиков он дает продвинутые возможности,
      а «среднестатический» программист использует небольшое и простое подмножество языка.
      Ну не должны архитекторы делать ядро и dsl для системы на языках со слабыми возможностями, ориентируясь на «средненькое».
      Scala это или Java или еще что, «среднестатический» программист пишет в основном на DSL. DSL ему делают более продвинутые люди. Для работы с этим DSL он использует небольшое и простое подмножество языка.


      1. senia
        26.08.2016 23:29
        +3

        Поддержу данный тезис своим опытом(наблюдал как джуниоры пишут на scala): единственное, что требуется джуниору, чтобы быстро начать писать на scala — code review. Можно даже книжку Одерского не читать, а писать по аналогии, главное — чтоб было кому одернуть.


      1. aibar
        27.08.2016 02:41

        «среднестатический» программист пишет в основном на DSL

        Неужели? Разве можно считать hibernate+spring+tomcat DSL-ом?


        1. solver
          27.08.2016 14:31
          +1

          Вообще-то да, именно об этом я и говорю.
          Большинство библиотек и фреймворков, это по сути DSL. Просто Java корявый язык для создания DSL.
          Чтобы понять о чем я, посмотрите на Slick для Scala, он делает почти тоже самое что и Hibernate. Но при этом выглядит более «DSL-но». Да, понятно, что это все не чистый DSL.
          Если перефразировать, то получится что-то вроде "«среднестатический» программист пишет в основном на библиотеках". Но тем не менее, суть высказывания от этого не меняется.


      1. JediPhilosopher
        27.08.2016 18:21
        -2

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


        Позволю себе не согласиться.

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

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

        Как кто-то тут писал: «то что в Хаскелле считается сложными паттернами, не рекомендуемыми к чрезмерному использованию, в Скале пихают в каждую библиотеку просто чтобы было и чтобы показать что они ничуть не хуже Хаскелла».

        Возможно когда я разберусь в языке лучше то тоже буду восхищаться им. Но пока что он меня слегка ужасает.


        1. solver
          28.08.2016 01:38
          +2

          Так это не язык ужасает, а отдельные личности разрабатывающие библиотеки и злоупотребляющие возможностями языка. Плохих примеров в любом языке полно, не надо на них ориентироваться.
          Если вы не можете даже REST-API написать без «дебри всяких имплиситов, перегруженных операторов в стиле ASCII-арта и вообще непонятных закорючек», то вы 100% делаете все не так)
          Не выбирайте левые библиотеки. Берите мейнстрим нормальный и никаких проблем не будет.


          1. ppopoff
            28.08.2016 02:54
            +1

            Согласен. Самолично видел "перегрузку" "операторов" на Java. Безумца ничто не остановит.


          1. JediPhilosopher
            29.08.2016 13:43

            Я вроде бы вполне мейнстрим и взял. Ту же Akka-HTTP. В итоге без тех же имплиситов нельзя сделать Unmarshaller из XML. А попытка воспользоваться джавовским XStream приводит к тому что чтобы просто получить текст тела запроса нужно монстрячить с Akka-Streams, в который оно там все обернуто.

            Конечно разобравшись во всем этом я потом это смог сделать. Но в том и дело что НЕ разбираться в этом не получится, и писать на скале совсем как на джаве тоже.


            1. solver
              29.08.2016 15:01
              +1

              >Но в том и дело что НЕ разбираться в этом не получится

              Рискую поломать ваш уютный мир, но у меня для вас плохие новости. В любой технологии надо разбираться. Иначе будут сплошные говнокод и говнорешения или необоснованные выводы «технология говно».

              >и писать на скале совсем как на джаве тоже.
              А с чего вы взяли, что это вообще можно и нужно делать?


              1. JediPhilosopher
                29.08.2016 20:13

                Так выше излагали мнение что

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


                По моему опыту использовать «небольшое и простое подмножество» довольно затруднительно, так как любая библиотека будет норовить вас окунуть в самые дебри по макушку.


                1. solver
                  29.08.2016 22:22

                  Как лихо вы фразу «небольшое и простое подмножество языка» интерпретировали в «писать совсем как на джаве».

                  >...любая библиотека будет норовить вас окунуть в самые дебри по макушку

                  Вы правда создаете для каждой используемой библиотеки кучу кастомных имплиситов, макросы, литералы Черча, рекурсивные типы, вложенные типы, которыми эмулируются функции и еще 100500 вещей с которыми можно «окунуться в самые дебри по макушку»?
                  Вы уверены, что вы все правильно понимаете и делаете?
                  Или для вас «окунуться в самые дебри по макушку» это написать пару импортов с готовыми имплиситами?


    1. guai
      30.08.2016 19:34

      чо это вдруг цейлон — недоскала, а не наоборот?
      или в скале овеществленные дженерики появились? или нормальный тулинг?


      1. senia
        30.08.2016 23:42

        «овеществленные дженерики» — это что-то вроде такого?

        def is[T: ClassTag](a: Any) = a match {
          case _: T => true
          case _ => false
        }
        is[String]("") // true
        is[String](1) // false
        

        А что вы подразумеваете под тулингом?


        1. guai
          31.08.2016 00:20
          +1

          нет, что-то типа is[SomeType[String]](a) || is[SomeType[Int]](a) — в рантайме сохраняющиеся овеществленные дженерики, в скале их не осилили.
          а под тулингом я подразумеваю возможность запилить для языка годную IDE, быструю и с мощными рефакторингами. у скалы с этим всегда траблы были, т.к. куча путей, которые надо проверить, чтобы понять, откуда чего могло взяться в данном контексте, IDE это делает на каждый чих.


          1. senia
            31.08.2016 08:08

            Да, выглядит забавно. Но это очевидное «пока» взаимодействию с java. Ибо SomeType точно не определен в *.java файле.
            Ну а про IDE — IDEA на данный момент вполне неплохо справляется. И жертвовать выразительными средствами языка ради упрощения написания IDE я не готов.


            1. guai
              31.08.2016 09:34

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


              1. Saffron
                31.08.2016 11:11
                +2

                scala presentation compiler — это и есть поддержка IDE. Берёшь ensime и поддерживаешь scala IDE в любимом редакторе.

                Овеществлённых генериков нет в jvm, и это проблема. Если добавить их на уровне языка, то а) будет проседать performance б) обламается interoperability. А именно в последнем заключается USP скалы среди jvm языков.


                1. guai
                  31.08.2016 16:52

                  а) а можете показать, как оно просело в скале? Ах, ну да :)
                  б) каким образом interoperability обламывается от овеществлённых дженериков?
                  И еще вопрос: в чем такая уникальность interoperability в скале, если попросту нет ни одного языка под jvm без интеропа с явой хоть в каком-то виде? А чаще в максимально полном виде, т.к. все понимают, что языки без интеропа никому не нужны.


                  1. Saffron
                    31.08.2016 20:53
                    +2

                    а) никак не просело, в скале нет овеществлённых генериков
                    б) ты можешь написать класс в скале, расширить его в яве, потом снова расширить в скале, потом расширить в яве. По дороге все пришлые конструкции, которых нет в яве, пропадут. В том числе овеществлённые генерики.

                    Скала устроена так, что вся магия происходит во время компиляции, а после неё остаётся только ява-совместимый байткод. Весь бойлерплейт, который должен быть — на месте, сгенерирован компилятором из синтаксического сахара.


                    1. taujavarob
                      01.09.2016 11:53

                      б) ты можешь написать класс в скале, расширить его в яве, потом снова расширить в скале, потом расширить в яве. По дороге все пришлые конструкции, которых нет в яве, пропадут.


                      Это не «скала» какая то, а «сахар». ;)


                    1. guai
                      01.09.2016 12:30

                      а) как же хорошо у вас получается, нет фичи — отлично, нечему тормозить :) Вы, видимо, оптимист.
                      А я пытался навести вас на мысль, что раз никто эту фичу еще не осилил, кроме цейлона, то нельзя со всей уверенностью утверждать, что от нее что-то там должно просесть. Да и что там может просесть? Чутка времени на загрузку чуть более толстых классов с большим количеством метаинформации — это не серьёзно. Если эту фичу не юзать, ничего она не отожрет. Но если она нужна, то альтернатива ей — куча геморроя с кодогенерацией или ручным протаскиванием этой метаинфы в рантайм.
                      б) то, что в одном нечастом кейсе у меня пропадет фича — это типа повод не делать ее вообще? зато в цейлоне эта фича будет работать в большинстве другого кода, где мне интероп не нужен.
                      «ява-совместимый байткод» — это что такое? такой байткод, который можно декомпилировать в валидную яву? у меня есть серьёзные подозрения, что скала этим свойством не обладает. пруфца не найдется?


                      1. Saffron
                        01.09.2016 13:22
                        +1

                        > эта фича будет работать в большинстве другого кода, где мне интероп не нужен.

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


                        1. guai
                          01.09.2016 16:23

                          Некорректно работать ничего не начнет.
                          Если я реализую в цейлоне явавский интерфейс — какие проблемы? В яве код, очевидно, написан так, чтоб использовать этот интерфейс, и нет разницы, что там наверчено помимо. Если передаю что-то из явы в цейлон — тоже нет проблем, компилятор меня вынудит сделать все проверки явно, чтоб я не напихал чего-то туда, куда не надо.
                          Раз вы считаете, что интероп это такая нужная в каждой строчке программы фича, то вы зря ратуете за скалу, вон котлин есть, там всё еще ближе к яве, рантайма нет. Или вообще xtend, который в явавские сорцы компиляется — красота же! А скала ни то ни сё, своя стандартная либа есть, а всех фичей, которые она позволяет сделать — нет.


                          1. Saffron
                            01.09.2016 19:36
                            +2

                            > Некорректно работать ничего не начнет.

                            Вы надеялись на типы, а ява объект их не имеет. Либо вы каждый раз проверяете, на месте ли информация о типах, либо допускаете ошибки в обработке коллекций, которые рассчитывают на информацию о типах для диспетчеризации (а для чего она ещё нужна?)

                            > Раз вы считаете, что интероп это такая нужная в каждой строчке программы фича, то вы зря ратуете за скалу, вон котлин есть

                            У котлина синтаксис не такой сладкий. Без паттерн матчинга жизнь не мила.


                            1. guai
                              01.09.2016 19:56

                              > либо допускаете ошибки в обработке коллекций
                              Не даст оно допустить ошибки, нет информации о типах — задай ее руками, иначе не соберется. Ну а вообще такие неудобства легко избегаются, если не пытаться сделать из цейлона назад яву, пишем на идеоматичном цейлоне — всё в ажуре, не зря ж там своя стандартная либа есть.
                              А в редких случаях, когда оно реально надо, ну вспоминаем боль явы, куда деваться…


                              1. Saffron
                                01.09.2016 22:30
                                +2

                                > такие неудобства легко избегаются, если не пытаться сделать из цейлона назад яву, пишем на идеоматичном цейлоне — всё в ажуре

                                А зачем тогда вообще нужна JVM? Обычно её выбирают, чтобы получить доступ к наработкам огромного java-мира, и к его программистской базе.


                                1. guai
                                  02.09.2016 14:14

                                  А я разве потеряю что-то, если буду юзать цейлоновские либы, когда они есть, и делать обёртки или писать интероп-код, если их нет? Я и на других языках так делаю. Есть гем для jruby — юзаю его, нет — ковыряюсь с явой.
                                  Не видел пока ни одного продукта, где бы не старались минимизировать/изолировать границу языков. Тут у нас скрипты на груви, тут dsl на котлине, тут легаси на яве и т.п.
                                  А вы почему-то говорите о том, чтобы все смешать в кучу, как о чем-то хорошем.


          1. 0xd34df00d
            01.09.2016 21:38

            А объясните для неджавистов, пожалуйста, про овеществленные дженерики. Мне этот пример ничего не поясняет, к сожалению.


            1. senia
              01.09.2016 22:10

              Проблема в type erasure.
              В Java дженерики существуют только во время компиляции. В рантайме все эти List<String> и MyClass<Double> превращаются в тыкву List<Object> и MyClass<Object>. Информации о типах в параметрах дженериков в рантайме теряется полностью. Но при желании ее можно сохранить.
              Простой пример — массивы. Если у вас есть класс List<T>, то вы не можете просто так написать метод toList такой, что List<String>::toArray() возвращал бы String[], а List<MyClass>::toArray() — MyClass[]. Так как массивы — не дженерики. Но это можно обойти, передав в метод информацию о рантайм типе.
              В java это делается явно — у метода появляется дополнительный параметр типа Class<T> и в методе он используется.
              В scala — неявно: у метода в сигнатуре появляется требование нужной информации (ClassTag в моем примере), которую может подставить компилятор.
              В цейлоне — еще более неявно — сигнатура метода меняется не программистом, а компилятором. В исходном коде нет явного указания, что метод требует дополнительную информацию о типе.

              Это все хорошо до тех пор, пока у вас есть дженерик методы, не нет дженерик классов в качестве аргументов. А они будут.
              В java нет способа отличить List<String> от List<Double>, кроме как проверить реальное содержимое. Более того List<Strind> и List<Object>, в который случайно положили только строки не отличаются вообще ни чем.
              Обойти это ограничение просто так нельзя. Единственный способ — добавлять информацию о типе в экземпляры дженерик классов. Цейлон пошел по этому пути. Но если вы пишете под jvm, то вам требуется возможность взаимодействия с огромным количеством библиотек, написанных на java. И тут всё становится печально: например как поведет себя библиотека, десериализующая xml или json, написанная на java с использованием рефлексии, если в качестве целевого класса ей передать ваш крутой класс с дополнительной информацией, сказать сложно, но точно не как вам хочется.
              Так что в scala выбрали другой путь: сохранять совместимость с java. И задачи, требующие информации о типах, в scala решаются во время компиляции. Ради этого там крайне гибкая система типов и мощный механизма макросов, на котором делают просто невероятные вещи.


              1. 0xd34df00d
                01.09.2016 22:16

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


                1. senia
                  01.09.2016 22:31

                  Не знаю… в scala есть typeclass и я не понимаю чем они похожи на дженерики.
                  С точки зрения C++ можно смотреть так: в java всего 9 типов данных: 8 примитивов (boolean, byte, short, char, int, long, float, double) и указатель. Всё. Действительно всё — больше ничего не может лежать на стеке, передаваться как параметры и храниться в полях объектов. Вообще это довольно удобно: размер указателя всегда одинаков, так что код, который может работать с различными указателями, очевидно легко реализовывать. Но иногда приходится проверять реализует ли объект, на который указывает указатель, нужный нам контракт. Благо компилятор в большинстве случаев расставит такие проверки без участия программиста. Вот только вся эта красивая система была написана до появления дженериков в java, так что можно смело считать, что их там нет. А есть они только при компиляции, чтобы компилятор мог еще лучше расставлять проверки.


                  1. 0xd34df00d
                    02.09.2016 05:51

                    Ну, для typeclasses тоже надо словари с собой таскать в рантайме. Я в этом плане.


                    1. senia
                      02.09.2016 11:11

                      Это да. ClassTag — это typeclass.


              1. Saffron
                02.09.2016 00:05

                > В scala — неявно: у метода в сигнатуре появляется требование нужной информации (ClassTag в моем примере), которую может подставить компилятор.

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


            1. guai
              02.09.2016 11:40

              в плюсах шаблон компиляется в конкретный тип столько раз, сколько наборов параметров ему дадим, в шарпе доходит до рантайма в виде шаблона, потом JITом по мере надобности овеществляется. В яве же шаблоны (дженерики) привернули потом, как могли. Там все варианты овеществляются в один конкретный класс, в котором метаинформации про типы параметров уже нет, везде вместо них натыкан bottom-тип Object (поэтому же нельзя скаляры использовать в дженериках). Короче, костыль.
              Но это можно сделать средствами языка, не обязательна поддержка от VM, просто в яве думали еще и о обратной совместимости. Хотя если сделают когда-то поддержку в VM, наверное, будет быстрее/компактнее.
              Разработчики скалы обещают эту фичу дольше, чем весь цейлон делался. И не только с этой одной фичей, но еще и с более мощной системой типов, модульностью и прочими ништяками. Вот к этому у меня и претензии :)


              1. senia
                02.09.2016 21:13

                В чем выражается более мощная система типов? После того, как на скале без макросов написал функцию, меняющую порядок аргументов каррированной функции на противополодный, мне сложно понять куда уж мощнее тьюринг-полного ЯП в системе типов.


                1. 0xd34df00d
                  02.09.2016 21:15

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

                  А на самом деле я не знаю, как адекватно формально определять мощность системы типов.


                1. guai
                  03.09.2016 19:56

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


                  1. senia
                    03.09.2016 21:29

                    Про полноту по Тьюрингу первое что нагуглил: https://michid.wordpress.com/2010/01/29/scala-type-level-encoding-of-the-ski-calculus/. Вообще когда речь заходит про вычисления на уровне системы типов, то лучше всего вспомнить shapeless. Хотя это уже несколько неспортивно с тех пор, как они стали использовать макросы.
                    Про кортежи: это всего-лишь набор классов. Тот же HList в shapeless не ограничен ни чем (при он реализован в сторонней библиотеке). И HList позволяет делать такие забавные вещи как, например, map. За ссылку на map по кортежу в цейлоне буду благодарен.

                    Дженерики высших порядков: я затрудняюсь вспомнить версию scala, в которой их не было. В год появления цейлона они точно были. Можете ознакомиться с кратким обзором фич библиотеки scalaz — библиотека ФП, вдохновленная haskell. Более подробный обзор.

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


                    1. guai
                      03.09.2016 22:01

                      map по кортежу в цейлоне вполне себе из коробки, кортеж является списком, каждый элемент которого — это объединение всего, что там есть в кортеже.
                      Дженерики в скале, я так понимаю, только первого ранга. Хотя тут терминология гуляет от источника к источнику, щас запутаемся… Короче, можно в скале замутить функцию, которая принимает типы, и возвращает типы, а потом запараметризовать дженерик не конкретным типом, а такой функцией? Насколько я знаю, нет.


                      1. senia
                        03.09.2016 22:15

                        Отлично. А zip двух кортежей?

                        Давайте конкретный пример. Подозреваю, что таки возможно, причем без макросов. Если не именно так, как вы себе это представляете, то функционально эквивалентным способом.


                      1. senia
                        04.09.2016 03:00

                        Уточните, пожалуйста, каков результат map по кортежу?
                        Просто я подразумевал, что это должен быть кортеж, причем типизированный. [Set[Int], Set[String]] map getFirst -> [Int, String].


                        1. guai
                          05.09.2016 12:05

                          Ну там вообще 2 варианта. Если мы из статического контекста берем индекс, какой элемент нам надо вынуть из кортежа, но у нас будет конкретный тип, если из динамического контекста, то работаем как с сиквенсом (ну, списком). На выходе тоже сиквенс. Но можно потом назад из него сделать именно тапл, хотя зачем он нужен в динамическом контексте — не понятно, т.к. работа с ним всё-равно осуществляется как со списком.
                          То же самое и с зипом (если я правильно понял, он должен из двух кортежей сделать кортеж пар). Или тупо в лоб надоставали элементы и сформировали новый кортеж, или как со списком, плюс, если надо, явное преобразование назад в тапл.
                          Насчёт тайпфункций вот тут описалово http://ceylon-lang.org/blog/2015/06/12/more-type-functions/
                          можно такое в скале?
                          Ну это я не как вызов, мне прост интересно. К системе типов скалы у меня претензий не много, ну пусть там вместо частных случаев общей схемы где-то запрограммлены особые кейсы — бох с ними, главное чтоб работало. Нечасто в такие дебри надо лезть.
                          Более конкретные претензии к непонятному вектору развития, к высокому порогу входа и к тому, что надо доложить сотни стайлгайдов к скале, чтоб ей можно было пользоваться в команде.


  1. senia
    26.08.2016 22:53
    +1

    Забавная статья: хочется возразить едва ли не на каждое предложение.

    Объявление лямбд: лямбда из котлина валидна в скале. Почему бы не написать их одинаково?

    В Kotlin нет необходимости в специальном apply методе
    Вообще-то фабричный метод apply — это далеко не только возможность избавиться от new. Это именно фабричный метод. Странно, что кто-то не видит разницы между указанием конкретного класса и вызовом фабричного метода.

    (если property объявлено как var то setter метод также будет присутствовать)

    Верно и для scala.

    Реализует JavaBean getter и setter
    Достигается в scala добавлением одной стандартной аннотации.

    Существует огромное количество подводных камней у подобного усложнения в использовании map или flatMap
    Хотелось бы увидеть пример. Но вообще Option и nullable не эквивалентны. В котлине изначально интересный подход, жаль изначальная красивая идея об интеграции с java кодом через аннотации или автоматический анализ (для стандартной библиотеки) разбилась о дженерики.

    Scala, конечно, поддерживает функциональный подход. Kotlin чуть в меньшей степени, но основные идеи поддерживаются.
    В scala есть typeclass. Назвать это небольшим отличием в плане поддержки ФП — некоторое преуменьшение.
    И автор красиво обошел отсутствие аналога do-notation в контексте ФП и коллекций. Лесенки flatMap не пугают?

    Вызов по имени — Это разрушает читабельность. Если функция передается было бы гораздо легче увидеть что передается указатель на функции при простом просмотре кода.
    Зато неявный this в лямбдах читабельность, видимо, резко повышает. Если кто не знает: method{ println(something * 2) }. something тут, кроме очевидного варианта, что он объявлен или импортирован выше, может быть полем неявного this. println, кстати, тоже.

    Решение всех проблем с call-by-name (и со странными операторами) очень простое: используйте инструменты по назначению. Пример использования по назначению черной магии в scala — async/await в виде библиотеки. Как в таких случаях без call-by-name — не представляю.

    Это приводит к ситуации, когда поведение кода значительно меняется в зависимости от того, что было импортировано.
    Из двух зол выбираем меньшее: иначе поведение будет зависеть от еще более неявных вещей. Например от того, как настроен сериализатор (его настройку еще найти надо). Я предпочту чтоб мой код переставал компилироваться если не импортирован метод сериализации для используемого класса (см upickle), чем ловить ошибки в рантайме.

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

    Действительно ли мне нужно знать разницу между "~%#>" и "~+#>"?
    Решение простое: не используйте безумные библиотеки. Вы же не используете библиотеки с методами в духе «абырвалг», хотя такие имена никто не запрещает.

    Медленное время компиляции.
    Проект, на котором я работал в прошлом году, собирался и деплоился локально минут 10. Написан он при этом был на java.
    Вообще скорость компиляции scala — известная проблема. Но она зачастую неплохо лечится разбиением на подпроекты (полезно не только для компиляции) и инкрементальной компиляцией.


  1. Sirikid
    26.08.2016 23:22
    +1

    Многие рассматривают Kotlin как новый язык, это не совсем верно, у него даже стандартной библиотеки (почти) нет, можно сказать альтернативный синтаксис для Java.


    1. UbuRus
      27.08.2016 09:11
      +2

      Мощное заявление.


    1. lany
      27.08.2016 16:15
      +3

      Всё же не соглашусь. Котлин больше, чем просто синтаксический сахар. Например, штуки вроде declaration-site variance и null-safety — это вполне серьёзные семантические концепции. Если язык заставляет думать по-другому, то это уже новый язык. Пусть библиотека пока скромная, с хорошей interoperability с джавой это не так важно. По сути в стандартную библиотеку Котлина надо включать только те вещи, где использование (а не написание) Котлин-кода даёт существенные преимущества. В остальных случаях переписывать существующие Java-библиотеки не имеет смысла.


  1. vsb
    27.08.2016 12:03
    +7

    Тоже разработал один небольшой проект на Kotlin и в дальнейшем дорабатывал его. Впечатления самые положительные. Язык на голову приятней Java. IDE абсолютно готова к работе (да, бывают какие-то глюки, но совсем некритично), баги компилятора встречал два раза (это до релиза было), оба раза без проблем обходил, оба раза они фиксились, после релиза багов не встречал.

    Scala мне кажется очень переусложнённым языком. Тоже использовал её несколько лет назад в одном мелком проекте (компилятор), больше использовать не буду. Если очень крутая команда — может быть и имеет смысл, но для большинства людей — нет. А вот Kotlin — вполне.


  1. wert_lex
    27.08.2016 22:08
    +1

    Вот у меня вопрос немного не по теме сравнения.
    А когда уже в Scala завезут нормальный, Scala-inspired веб-фреймворк? Что-то уровня нодовского Express, только с батарейками из Scala.
    Сейчас объясню, и если не прав — поправьте.
    Есть Netty, который очень низкоуровневый, несомненно хорош, но для простенького REST API в десяток методов и две формы — это явно слишком низкоуровневый инструмент.

    Есть Play2, в который всё подряд понапихали уже. А в качестве вишенки на торте вкорячили Runtime DI (да, в типобезопасный язык; да, знаю про интероп с Java). Хотя, вроде бы можно там как-то устроить себе Compile Time DI, но выглядит это всё как-то сложно и странно. Зато тут очень классная Json библиотека.

    Есть/был Spray. Который прикольно лег на модель акторов, и на котором настолько же невозможно писать читаемый код. Spray, который теперь больше не развивается, а стал, akka-http, и где-то год назад оно только более-менее завелось до того состояния, чтобы им не страшно было пользоваться.

    Есть/был(?) Scalatra. Который выглядел так, будто неплохо зайдет для наколенного творчества, но последняя версия была 20 декабря 2015.

    Ну вот теперь вопрос: куда бежать-то? Play кажется повернул куда-то не туда. Http streaming вроде завезли, но во всяких мелких Rest API обычно хватает ровно одного chunk-а. Spray из неплохой идеи и паршивой реализации как-то так и не расцвёл в готовое решение (или расцвёл?).
    Да, а еще lightbend есть, а scala 2.12 — нет.


    1. Saffron
      27.08.2016 22:38

      Я вебом не интересуюсь, но на обложке скалы нарисован Lift, это не оно?


    1. senia
      27.08.2016 22:49

      Что не так с Play? Лично я не фанат плея, но использовать Runtime DI там не заставляют. Можно подключить любой по своему усмотрению.

      Akka-http, как по мне, так отличная идея и реализация хорошая.

      Что не так с 2.12? Были какие-то сорванные сроки? 2.12-M5 вышла 29 июня.
      Лично мне интереснее dotty, но там со сроками все плохо по очевидным причинам.

      Кстати, если хочется действительно «Scala-inspired» подход «для простенького REST API в десяток методов и две формы», то есть autowire, но это для бескомпромиссных.


    1. solver
      28.08.2016 01:42
      +2

      Чем Akka стек не устроил?
      Вполне себе нормальный вариант. Практически как Spring, универсальный солдат для основы приложения)
      Http модуль у нее вполне себе нормально работает, что не устраивает-то?