Pull to refresh

Comments 132

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

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

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

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

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

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


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

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

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


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

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

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

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

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

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

Можете привести примеры кода?
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 ->
            // ...
        }
    }

Зависает. Но не на процессинге линии, а на чтении.

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

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

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

Баги таки бывают. Но это скорее детские болезни, чем какие-то серьезные ошибки в дизайне языка. Единственное что утомляет это медленная компиляция под андроид.
Советую посмотреть доклад Антона Кекса «Anton Keks — Kotlin in real projects: pragmatic opinion on pragmatic language (Ru)»
Всё что я увидел из этой статьи, по большому счету, что kotlin нравится тем, что в нем нет некоторых возможностей scala и парой мест, где дело исключительно во вкусе. И, получается, что из-за этого некоторая компания год назад перешла с одного языка на другой. И при этом почти сразу после появления второго языка. Есть подозрение, что если эта компания и существует, то состоит она примерно из одного сотрудника.
Сам язык появился не год назад, а гораздо раньше.
Но использовать его в продакшене до первой стабильной версии никто бы не стал, поэтому имеет смысл говорить именно об этой дате.
Кстати интересно, а вы пробовали написать что-нибудь на Kotlin? Особенно в совокупности с gradle?
Я всё жду статью, которая объяснит мне, зачем это делать. Пока лишь вижу какую-то субъективщину и вкусовщину. К тому же ряд возможностей scala, которые некоторые пытаются занести в недостатки, мне нравятся и их будет не хватать. Тот же implicit можно использовать безопасно и удобно в куче сценариев. А без pattern matching'а вообще не понятно как писать компактный код, это ж java какая-то получается.
А без 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. И совокупное впечатление от языка только положительное.
Вряд ли какая-то статья даст вам конкретный ответ на этот вопрос, пока сами не попробуете.

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

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

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

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

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

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

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

А так полностью согласен.
reified type parameters связаны как раз именно с инлайном

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

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

Из рефлекшена, но в итоге TypeTag в Scala позволяет «прокидывать» информацию о типе в рантайм. Reified type в Kotlin делает примерно тоже самое.
вы его начали использовать до релиза?
Чуть раньше, начиная с беты начали делать на нем небольшие компоненты и небольшой проект.
> Implicit преобразования — Это то что я действительно ненавижу. Это приводит к ситуации, когда поведение кода значительно меняется в зависимости от того, что было импортировано.

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

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

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

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

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

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

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

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

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

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

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

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

автор как раз и говорит что ему не хватает pattern matching в kotlin
Всё-таки не view bounds (которые устарели), а context bounds.
А ешё вы не упомянули скаловскую фичу View Bound, без которой достаточно кисло в некоторых случаях, когда хочется типобезопасно выразить полиморфизм. И она тоже работает через implicit.

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

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

Люди сравнивают синтиаксис: Вот тут у меня 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 :)

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

з.ы. клоню к тому, что мы сперва получаем (ага), после чего применяем к результату саркастическое конечно :-)
пожалуйста, не сравнивайте языки по синтаксису.


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


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


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

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

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

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

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

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

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

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

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

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

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

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


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

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


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

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

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

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


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


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


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

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


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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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


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

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

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


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

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

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

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

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

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

Не верю. scala-native — это академический проект, и вряд ли джетбрейновцы добьются большего. Потому что kotlin-native, как и scala-native, требует как минимум java-native, а это такой вожделенный плод, что если бы его можно было достать, кто-нибудь из больших корпораций уже сорвал бы его.
scala.sj продемонстрировал как можно обойтись без java-native. Правда тут у scala большое преимущество: огромное количество библиотек, написанных на scala (без java, кроме стандартной библиотеки), которые легко собрать под scala.js. Колтин же даже своей стандартной библиотеки не имеет.
У Kotlin есть все тоже самое что написано для Java, и даже больше. Никто не мешает вам даже либы scala использовать
Вы, кажется, выпали из обсуждаемого контекста. Тут речь исключительно про Kotlin Native и scala-native.
По аналогии со scala.js: надо либо изобрести java-native (чтобы использовать java библиотеки из Kotlin Native), либо не использовать java библиотеки из Kotlin Native.
Saffron высказал предположение, что первый путь затруднителен.
В scala.js пошли по второму пути: там просто не используются java библиотеки, за исключением портированой части стандартной библиотеки. Котлин же себе такого позволить не может: он гораздо сильнее зависит от java окружения, чем scala.
Чисто на скале, без задействования мощи JVM и рефлекшна, пишут по большей части ФП-фрики, радикальное крыло скалы программистов, всё на свете выражающее через типоклассы, о которых так нелестно отзывался автор статьи. Так что в натив или яваскрипт идёт не та скала, которая better java, а та скала, которая убогое подобие хаскеля и ML.

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

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


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

UFO just landed and posted this here

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


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

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


Вот поэтому он и не взлетает.
Это распространенное заблуждение. Очень жаль, что его культивируют.
Большой плюс Scala как раз в том, что для продвинутых разработчиков он дает продвинутые возможности,
а «среднестатический» программист использует небольшое и простое подмножество языка.
Ну не должны архитекторы делать ядро и dsl для системы на языках со слабыми возможностями, ориентируясь на «средненькое».
Scala это или Java или еще что, «среднестатический» программист пишет в основном на DSL. DSL ему делают более продвинутые люди. Для работы с этим DSL он использует небольшое и простое подмножество языка.
Поддержу данный тезис своим опытом(наблюдал как джуниоры пишут на scala): единственное, что требуется джуниору, чтобы быстро начать писать на scala — code review. Можно даже книжку Одерского не читать, а писать по аналогии, главное — чтоб было кому одернуть.
UFO just landed and posted this here
Вообще-то да, именно об этом я и говорю.
Большинство библиотек и фреймворков, это по сути DSL. Просто Java корявый язык для создания DSL.
Чтобы понять о чем я, посмотрите на Slick для Scala, он делает почти тоже самое что и Hibernate. Но при этом выглядит более «DSL-но». Да, понятно, что это все не чистый DSL.
Если перефразировать, то получится что-то вроде "«среднестатический» программист пишет в основном на библиотеках". Но тем не менее, суть высказывания от этого не меняется.
а «среднестатический» программист использует небольшое и простое подмножество языка.


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

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

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

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

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

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

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

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

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

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

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


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

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

Вы правда создаете для каждой используемой библиотеки кучу кастомных имплиситов, макросы, литералы Черча, рекурсивные типы, вложенные типы, которыми эмулируются функции и еще 100500 вещей с которыми можно «окунуться в самые дебри по макушку»?
Вы уверены, что вы все правильно понимаете и делаете?
Или для вас «окунуться в самые дебри по макушку» это написать пару импортов с готовыми имплиситами?
UFO just landed and posted this here
«овеществленные дженерики» — это что-то вроде такого?
def is[T: ClassTag](a: Any) = a match {
  case _: T => true
  case _ => false
}
is[String]("") // true
is[String](1) // false

А что вы подразумеваете под тулингом?
UFO just landed and posted this here
Да, выглядит забавно. Но это очевидное «пока» взаимодействию с java. Ибо SomeType точно не определен в *.java файле.
Ну а про IDE — IDEA на данный момент вполне неплохо справляется. И жертвовать выразительными средствами языка ради упрощения написания IDE я не готов.
UFO just landed and posted this here
scala presentation compiler — это и есть поддержка IDE. Берёшь ensime и поддерживаешь scala IDE в любимом редакторе.

Овеществлённых генериков нет в jvm, и это проблема. Если добавить их на уровне языка, то а) будет проседать performance б) обламается interoperability. А именно в последнем заключается USP скалы среди jvm языков.
UFO just landed and posted this here
а) никак не просело, в скале нет овеществлённых генериков
б) ты можешь написать класс в скале, расширить его в яве, потом снова расширить в скале, потом расширить в яве. По дороге все пришлые конструкции, которых нет в яве, пропадут. В том числе овеществлённые генерики.

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


Это не «скала» какая то, а «сахар». ;)
UFO just landed and posted this here
> эта фича будет работать в большинстве другого кода, где мне интероп не нужен.

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

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

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

У котлина синтаксис не такой сладкий. Без паттерн матчинга жизнь не мила.
UFO just landed and posted this here
> такие неудобства легко избегаются, если не пытаться сделать из цейлона назад яву, пишем на идеоматичном цейлоне — всё в ажуре

А зачем тогда вообще нужна JVM? Обычно её выбирают, чтобы получить доступ к наработкам огромного java-мира, и к его программистской базе.
UFO just landed and posted this here
UFO just landed and posted this here
Проблема в 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 решаются во время компиляции. Ради этого там крайне гибкая система типов и мощный механизма макросов, на котором делают просто невероятные вещи.
UFO just landed and posted this here
Не знаю… в scala есть typeclass и я не понимаю чем они похожи на дженерики.
С точки зрения C++ можно смотреть так: в java всего 9 типов данных: 8 примитивов (boolean, byte, short, char, int, long, float, double) и указатель. Всё. Действительно всё — больше ничего не может лежать на стеке, передаваться как параметры и храниться в полях объектов. Вообще это довольно удобно: размер указателя всегда одинаков, так что код, который может работать с различными указателями, очевидно легко реализовывать. Но иногда приходится проверять реализует ли объект, на который указывает указатель, нужный нам контракт. Благо компилятор в большинстве случаев расставит такие проверки без участия программиста. Вот только вся эта красивая система была написана до появления дженериков в java, так что можно смело считать, что их там нет. А есть они только при компиляции, чтобы компилятор мог еще лучше расставлять проверки.
UFO just landed and posted this here
Это да. ClassTag — это typeclass.
> В scala — неявно: у метода в сигнатуре появляется требование нужной информации (ClassTag в моем примере), которую может подставить компилятор.

Но при этом ClassTag работает только для тех классов, которые компилятор может вывести статически на этапе компиляции, и в рантайме эта информация теряется. Потому овеществления дженериков всё же в скале нет.
UFO just landed and posted this here
В чем выражается более мощная система типов? После того, как на скале без макросов написал функцию, меняющую порядок аргументов каррированной функции на противополодный, мне сложно понять куда уж мощнее тьюринг-полного ЯП в системе типов.
UFO just landed and posted this here
UFO just landed and posted this here
Про полноту по Тьюрингу первое что нагуглил: 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. Вполне удобно, но поддержка на уровне синтаксиса языка, несомненно, была бы лучше.
UFO just landed and posted this here
Отлично. А zip двух кортежей?

Давайте конкретный пример. Подозреваю, что таки возможно, причем без макросов. Если не именно так, как вы себе это представляете, то функционально эквивалентным способом.
Уточните, пожалуйста, каков результат map по кортежу?
Просто я подразумевал, что это должен быть кортеж, причем типизированный. [Set[Int], Set[String]] map getFirst -> [Int, String].
UFO just landed and posted this here
Вообще-то пример с map и zip по кортежу как раз показывает, что система типов в scala более мощная и это в ceylon «запрограммлены особые кейсы». Заметьте: shapeless — отдельная библиотека, не предусмотренная разработчиками языка изначально. Но она использует систему типов scala таким образом, что сохраняет больше информации о типах, чем кортежы в ceylon.

можно такое в скале?


Ничего нереализуемого я там не увидел. Не все делается точно так же. Иногда более многословно. Напишите интересующий вас пример на ceylon (с указанием цели) и я перепишу его вам на scala.

Вектор развития мне вполне понятен. И очень интересен. В ближней перспективе — это стабилизация 2.12 (2.12-M5). В дальней — это dotty.
Про стайлгайды: не заметил. Нужно только review (куда же без него).
UFO just landed and posted this here
Нет предела совершенству. Они математическую модель под систему типов подвели. Поделитесь ссылкой на строгое доказательство корректности системы типов в ceylon?
Что должны доказать ссылка на архивный тред в 74 комментария? Что кто-то с кем-то не согласен? Тоже мне новость.
На предыдущие мои вопросы ответите (про пример кода на ceylon с использованием type function) или сворачиваем обсуждение?
UFO just landed and posted this here
Ну еще не подвели же, еще только собираются попробовать подвести.
Система типов для dotty уже готова.
Все-таки я бы предпочел пообщаться с тем, кто написал «более мощной системы типов» про цейлон относительно скалы. Пока из вас удалось вытянуть наличие пересечений и объединений. И то, что кортежи в цейлоне не дотягивают до HList (хотелось бы знать возможно ли реализовать HList в цейлоне).
Все мои вопросы о примерах кода вы игнорируете.
2 конкретных вопроса:
  1. Есть тип A с полем l типа F1 и тип B с полем l типа F2. Какой будет тип поля l у объединения типов A и B и пересечения типов A и B
  2. Пример кода на цейлоне, разворачивающего порядок аргументов каррированной функции. 2 аналогичных примера кода на scala можете найти здесь.
UFO just landed and posted this here
Эта ветка каментов началась с заявления, что цейлон — это, якобы, недоскала
Не от меня. Я же отвечал исключительно на ваши заявления.
Типы пересечения и объединения уже делают систему типов более мощной.
Я выше написал, что в scala есть и пересечение и объединение. Пересечение из коробки, объединение — в библиотеках.
Овеществленные дженерики убивают взаимодействие с java, а «нормальность» синтаксиса — вкусовщина.
в виде какой-то левой либы
Возможность расширять бызовую концепцию библиотеками, а не хардкодом в компиляторе, как раз и отличает более продуманный и фундаментальный подход.
Почему-то они решили это сделать только после того, как это сделали в целоне :)
Влияние цейлона вы явно переоцениваете.
Насколько я понял, HList — это то самое, чем являются кортежи в цейлоне.
map, zip и другие операции по HList возвращают HList, соответственно типизированный. Выше мы выяснили, что map по кортежу в цейлоне теряет информацию о структуре кортежа (на уровне типов).
У объединения типов A и B будет тип A|B, доступ же к полям возможен только после явной проверки конкретного объекта на конкретный тип
Это то, как работает объединение в shapeless(в библиотеке), но не то, что реализовано в dotty. Благодарю за информацию.

Про перестановку. Для начала каррированная функция — функция, принимающая 1 аргумент. Если требуется более одного аргумента, то функция возвращает новую функцию. Например требуется 3 аргумента: Int, String и Long. Результат — String. В синтаксисе scala такая функция будет иметь тип Int => String => Long => String. В синтаксисе java — Function<Integer, Function<String, Function<Long, String>>>. Вызов такой функции в scala: func(1)(«str»)(666L), в java — func.apply(1).apply(«str»).apply(666).
Задача: написать метод, который, приняв каррированную функцию с любым количеством аргументов вернет новую — с обратным порядком аргументов.
Например если в качестве аргумента будет Function<Integer, String>, то результатом должна быть Function<Integer, String>, если аргумент Function<Integer, Function<Long, String>>, то результат — Function<Long, Function<Integer, String>>, если аргумент Function<Integer, Function<String, Function<Long, String>>>, то результат — Function<Long, Function<String, Function<Integer, String>>>
Забавная статья: хочется возразить едва ли не на каждое предложение.

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

В 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 — известная проблема. Но она зачастую неплохо лечится разбиением на подпроекты (полезно не только для компиляции) и инкрементальной компиляцией.
UFO just landed and posted this here

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

UFO just landed and posted this here
Вот у меня вопрос немного не по теме сравнения.
А когда уже в 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 — нет.
Я вебом не интересуюсь, но на обложке скалы нарисован Lift, это не оно?
Что не так с Play? Лично я не фанат плея, но использовать Runtime DI там не заставляют. Можно подключить любой по своему усмотрению.

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

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

Кстати, если хочется действительно «Scala-inspired» подход «для простенького REST API в десяток методов и две формы», то есть autowire, но это для бескомпромиссных.
Чем Akka стек не устроил?
Вполне себе нормальный вариант. Практически как Spring, универсальный солдат для основы приложения)
Http модуль у нее вполне себе нормально работает, что не устраивает-то?
Sign up to leave a comment.

Articles