В последнее время активную популярность набирает Kotlin. А что если попробовать выбрать более экзотические языки, и применить к ним те же аргументы? Статья написана по мотивам этой, практически повторяя все аргументы за Kotlin. Основная задача: показать, что Ceylon может практически тоже самое, что и Kotlin, применительно к Java. Но кроме этого у Ceylon есть кое-что еще, что будет описано в следующей статье.


Хочу рассказать о новом языке программирования, который называется Ceylon, и объяснить, почему вам стоит использовать его в своём следующем проекте. Раньше я писал на Java (много и долго, более 10 лет, начиная с Java 1.4 и заканчивая Java 8), и Java мне нравилась. Затем на меня большое впечатление произвела Scala, в результате чего Java как язык стал любить несколько меньше. Но судьба свела меня с языком Сeylon, и в последние полтора года мы пишем на Ceylon везде, где только можно. В реальных коммерческих проектах, правда внутренних. И в данный момент я не представляю себе ситуации, в которой лучше было бы выбрать Java, я не рассматриваю Java как язык, на котором стоит начинать новые проекты.


Ceylon разработан в Red Hat, автор языка — Gavin King, известный по такому фреймворку как Hibernate. Он создавался людьми, которые хорошо понимают недостатки Java, основная цель заключалась в решении сугубо прикладных задач, обеспечение максимально легкой читаемости кода, избегание любых неоднозначностей и подводных камней, во главу всего стала предсказуемость и структурная красота языка. Также большое внимание уделялось приемлемому времени компиляции. В настоящее время версия языка 1.3.2, непосредственно я познакомился с языком, когда вышла версия 1.2.0.


Хотя Ceylon компилируется в JavaScript, я сконцентрируюсь на его первичной среде — JVM.


Итак, несколько причин, почему вам следует полностью переходить на Ceylon (порядок совпадает с одноименными пунктами соответствующей Kotlin статьи):


0# Совместимость с Java


Также, как и Kotlin, как и Scala, Ceylon на 100 % совместим с Java. Вы можете в буквальном смысле продолжать работать над своим старым Java-проектом, но уже используя Ceylon. Все Java-фреймворки также будут доступны, и, в каком бы фреймворке вы ни писали, Ceylon будет легко принят упрямым любителем Java. Можно без проблем вызывать из Java Ceylon код, также без проблем вызывается Java код.


1# Знакомый синтаксис


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


class Foo(String a) {

    String b= "b";           //  unmodifiable
    variable Integer i = 0;  // variable means modifiable

    void hello() {
        value str = "Hello";
        print("``str`` World");
    }

    Integer sum(Integer x, Integer y) {
        return x + y;
    }

    Float maxOf(Float a, Float b) => if (a > b) then a else b
}

Соответственно можно без проблем продолжать писать в Java стиле на Ceylon.


2# Интерполяция строк


Это как бы более умная и читабельная версия String.format() из Java, встроенная в язык:


value x = 4;
value y = 7;
print("sum of ``x`` and ``y`` is ``x + y``") ; // sum of 4 and 7 is 11

ИМХО синтаксис здесь будет поприятнее, чем в Kotlin, с Java даже не хочется сравнивать.


3# Выведение типа


Ceylon будет выводить ваши типы, если вы посчитаете, что это улучшит читабельность:


value a = "abc";                         // type inferred to String
value b = 4;                             // type inferred to Integer

Float c = 0.7;                   // type declared explicitly
List<String> d = ArrayList<String>();     // type declared explicitly

4# Умные приведения типов (Smart Casts)


Компилятор Ceylon отслеживает вашу логику и по мере возможности автоматически выполняет приведение типов, т. е. вам больше не нужны проверки instanceof после явных приведений:


if (is String obj) {
    print(obj.uppercased)     // obj is now known to be a String
}

5# Интуитивные равенства (Intuitive Equals)


Можно больше не вызывать явно equals(), потому что оператор == теперь проверяет структурное равенство:


value john1 = Person("John"); //we override equals in Person
value john2 = Person("John");
print(john1 == john2);    // true  (structural equality)
print(john1 === john2);    // false  (referential equality)

6# Аргументы по умолчанию


Больше не нужно определять несколько одинаковых методов с разными аргументами:


void build(String title, Integer width = 800, Integer height = 600) {
    return Frame(title, width, height);
}

7# Именованные аргументы


В сочетании с аргументами по умолчанию именованные аргументы избавляют от необходимости использовать Строителей:


build("PacMan", 400, 300)                           // equivalent
build {title = "PacMan"; width = 400; height = 300;}  // equivalent
build {title = "PacMan"; height = 300;}  // equivalent with default width

8# Выражение switch


Оператор ветвления заменён гораздо более читабельным и гибким в применении выражением switch:


switch (obj)
case(1)                              { print("x is 1"); }
case(2)                              { print("x is 2"); }
case(3 | 4)                          { print("x is 3 or 4"); }
case(is String)                      { print ("x is String"); }
case([Integer a, Float b, String c]) {print ("x is tuple with Integer ``a``, Float ``b`` and String ``c``");}
else                                 { print("x is out of range");}

switch может работать как выражение, также результат switch может быть присвоен переменной:


Boolean|IllegalStateException res = 
    switch(obj)
    case(null) false
    case(is String) true
    else IllegalStateException();

Это не полноценный pattern matching, но для большинства случаев хватает и текущего функционала.


В отличие от Kotlin у Ceylon требуется, чтобы к switch все условия были disjoint, то есть не пересекались, что для switch гораздо более логично. Если требуется сопоставление по диапазону или условия могут пересекаться, то нужно использовать обычный if.


9# Свойства


Можно добавить публичным полям кастомное поведение set & get, т. е. перестать набивать код безумными геттерами и сеттерами.


class Frame() {
    variable Integer width = 800;
    variable Integer height = 600;

    Integer pixels => width * height;
}

10# Data Class


К сожалению данного функционала пока нет. Очень хотелось бы иметь иммутабельные классы, у которых автоматом переопределен toString(), equals(), hashCode() и copy(), но, в отличие от Java, не занимали 100 строк кода.


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


class Person(shared String name, 
             shared String email,
             shared Integer age) extends DataObject() {}

value john = Person("John", "john@gmail.com", 112);
value johnAfterBirhstday = john.copy<Person>({`Person.age`->113;});
assertEquals(john, john.copy<Person>());
assertEquals(john.hash, john.copy<Person>().hash);

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


11# Перегрузка оператора (Operator Overloading)


Заранее определённый набор операторов, которые можно перегружать для улучшения читабельности:


class Vec(shared Float x, shared Float y) satisfies Summable<Vec> {
    shared actual Vec plus(Vec v)  => Vec(x + v.x, y + v.y);
}

value v = Vec(2.0, 3.0) + Vec(4.0, 1.0);

12# Деструктурирующие объявления (Destructuring Declarations)


Некоторые объекты могут быть деструктурированы, что бывает полезно, к примеру, для итерирования map:


for ([key -> [val1, val2, val3]] in map) {
    print("Key: ``key``");
    print("Value: ``val1``, ``val2``, ``val3``");
}

13# Диапазоны (Ranges)


Для улучшения читабельности:


for (i in 1..100) { ... } 
for (i in 0 : 100) { ... }
for (i in (2..10).by(2)) { ... } 
for (i in 10..2) { ... }  
if (x in 1..10) { ... }

В отличие от Kotlin обошлось без ключевого слова downTo.


14# Функции-расширения (Extension Functions)


Их нет. Возможно появится, в ранних спецификациях языка такая возможность рассматривалась. Но вместо функций расширений в принципе работают top level функции. Если мы, допустим, хотим добавить к классу String метод sayHello, то "world".sayHello() выглядит не намного лучше чем sayHello("world"). В будущем они могут появиться.


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


15# Безопасность Null


Java следует называть почти статично типизированным языком. Внутри него переменная типа String не гарантированно ссылается на String — она может ссылаться на null. И хотя мы к этому привыкли, это снижает безопасность проверки на статичное типизирование, и в результате Java-разработчики вынуждены жить в постоянном страхе перед NPE.


В Ceylon эта проблема решена посредством разделения на типы, допускающие и не допускающие значение null. По умолчанию типы не допускают null, но их можно преобразовать в допускающие, если добавить ?:


variable String a = "abc";
a = null;                // compile error

variable String? b = "xyz";
b = null;                // no problem

За счет функционала union types String? это просто синтаксический сахар для String|Null. Соответственно можно написать:


variable String|Null с = "xyz";
с = null;                // no problem

Ceylon заставляет вас бороться с NPE, когда вы обращаетесь к типу, допускающему null:


value x = b.length        // compile error: b might be null

Возможно, выглядит громоздко, но благодаря нескольким своим возможностям действительно полезно. У нас всё ещё есть умные приведения типов, когда типы, допускающие null, преобразуются в не допускающие:


if (!exists b) { return; }
value x = b.length        // no problem

Также можно использовать безопасный вызов ?., он возвращает значение null вместо бросания NPE:


value x = b?.length;       // type of x is nullable Int

Можно объединять безопасные вызовы в цепочки, чтобы избегать вложенных проверок если-не-null, которые иногда мы пишем в других языках. А если нам по умолчанию нужно не null-значение, то воспользуемся elvis-оператором else


value name = ship?.captain?.name else "unknown";

Если всё это вам не подходит и вам совершенно точно нужны NPE, то скажите об этом явно:


value x = b?.length else NullPointerException()  // same as below
assert(!NullPointerException x);

16# Улучшенные лямбды


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


value sum = (Integer x, Integer y) => x + y;  // type: Integer(Integer, Integer)
value res = sum(4,7)                      // res == 11

Соответственно синтаксис может быть:


numbers.filter( (x) => x.isPrime() );
numbers.filter(isPrime)

Это позволяет нам писать лаконичный функциональный код:


    persons
        .filter ( (it) => it.age >= 18)
        .sort(byIncreasing(Person.name))
        .map ( Person.email )
        .each ( print );

Система лямбд плюс синтаксические особенности языка, делает Ceylon неплохим инструментом для создания DSL. Пример DSL, похожего на Anko, в синтаксисе Ceylon:


 VerticalLayout {
    padding = dip(30);  {
    editText {
        hint = "Name";
        textSize = 24.0;
    },
    editText {
        hint = "Password";
        textSize = 24.0;
    },
    button {
        "Login";
        textSize = 45.0;
    } }
};

17# Поддержка IDE


Между прочим, она достаточно неплохая. Есть eclipse плагин, есть IDEA плагин. Да, по части фич и багов все несколько хуже, чем в Scala или Kotlin. Но в принципе работать можно и достаточно комфортно, проблемы IDE на скорости разработки практически не сказываются.


Итого, если брать сильные стороны Kotlin, Ceylon уступает Kotlin отсутствием функционала DataObject (который можно эмулировать самостоятельно средствами библиотек). В остальном он обеспечивает не меньшие возможности, но с более приятным для чтения синтаксисом.


Ну и так же, как и на Kotlin, на Ceylon можно писать для Android.


Прочитав вышесказанное, может сложиться впечатление — а зачем нам это? Тоже самое есть и в Kotlin, практически 1 в 1.


А то, что в Ceylon есть вещи, которых нет ни в Kotlin, ни в Scala, и за счет этих вещей сам язык во многом гораздо лучше, чем другие языки. Например union types, intersection types, enumerated types, более мощные generics, модульность, herd, аннотации и метамодель, кортежи, for comprehensions. Что реально меняет подход к программированию, позволяет писать гораздо более надежный, понятный и универсальный код. Но об этом в следующей части.


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

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


  1. Ockonal
    07.06.2017 13:15
    +15

    :)


  1. NikNik77771
    07.06.2017 13:16

    Лучшая статья по Ceylon за последние 3 года. Сам использую и всем рекомендую. Надеюсь, что язык будет и дальше развиваться.


  1. bohdan4ik
    07.06.2017 13:34
    +5

    Основаная проблема Ceylon — нет вакансий.


    1. NikNik77771
      07.06.2017 13:49

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


    1. elmal
      07.06.2017 13:52

      Одна вакансия в Питере точно есть :). А во вторых, на Java тоже нет вакансий ;). Ибо вакансия идет на определенную предметную область под определенные задачи, язык дело десятое. Если умеешь программировать нормально на любом языке и обладаешь навыками в предметной области — без проблем перейдешь.


      1. bohdan4ik
        07.06.2017 13:59
        +2

        Ребят, я не говорю, что боюсь изучать новую платформу или язык. Я говорю о том, что эти знания несильно востребованы на рынке. По опыту, весьма часто требования диктует не разработчик (особенно новый, особенно, в моём случае, джун-мидл, поскольку не занимаюсь, увы, JVM или компиляцией экзотики в JS), а заказчик или команда. Такие дела.


        1. elmal
          07.06.2017 14:10

          Относительно востребованности на рынке. Если у человека в резюме стоит экзотический язык, например Common Lisp — с вероятностью процентов 90 это весьма приличный разработчик. И чем более это экзотический язык, тем интереснее такой кандидат для тех, кто ищет разработчиков, а не желающих просто кодировать всякие CRUD для базы. Однозначно есть люди, которые это понимают. Я, например, один раз даже на Ceylon делал тестовое задание для конторы, которая пишет на Java и Kotlin. Реально произвело фурор :).


          1. lany
            07.06.2017 19:52
            +1

            Если у человека в резюме стоит экзотический язык, например Common Lisp — с вероятностью процентов 90 это весьма приличный разработчик.

            Либо он учился на математическом факультете, где учат только лиспу, умеет доказывать теоремы, но к практическому программированию не готов :-)


            1. elmal
              07.06.2017 19:56

              Что то я не встречал студентов-математиков со знанием Лиспа :). Я лучше не буду про преподавание ИТ специальностей в ВУЗах, ибо будут непечатные слова. Так скажем, типичный выпускник прикладной математики в лучшем случае в настоящее время паскаль знает.
              Обычно изучается это все самостоятельно, SICP и тому подобное. Но я реально знаю двух людей с 4-мя годами коммерческого опыта на Common Lisp.


              1. mikhanoid
                07.06.2017 21:55
                -1

                Сейчас учат Python


            1. mikhanoid
              07.06.2017 21:53

              Либо ему просто стало скучно 90% рабочего времени тратить на ковыряние в памяти, указателях и интерфейсах, и он решил выйти на 80-ый уровень искусства программирования.


          1. sshikov
            07.06.2017 22:23
            +1

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


    1. sshikov
      07.06.2017 22:21

      Знаете, за последние лет 10 наверное, я ни разу не встречал такого проекта, где бы я не мог обосновать руководству или заказчику, что надо писать на таком-то инструменте.

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

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


    1. guyu
      14.06.2017 20:17
      -1

      Основаная проблема Ceylon — нет вакансий.


      Эта основная проблема только для кодеров.

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


  1. DenimTornado
    07.06.2017 13:46

    Простите за профанский вопрос, я к вам из JS…
    Почему в пункте 5 при "===" получаем false?


    1. elmal
      07.06.2017 13:53
      +1

      === сравнивает значения указателей. То есть обычное == в Java. А == Ceylon отображается на .equals в Java.


      1. lany
        07.06.2017 19:54

        С этими равенствами, кстати, я уже в Котлине обжёгся.


        if(type === TYPE_VARIABLE || type === TYPE_PARAMETER || type == TYPE_FUNCTION || 
           type === TYPE_METHOD || type === TYPE_FIELD) { ... }

        Заметили опечатку? В джаве такая опечатка невозможна, а в Котлине/Цейлоне — легко (и я их видел в реальном коде).


        1. elmal
          07.06.2017 20:08

          Опечатку то я заметил.
          Ну, в Ceylon я б такое написал как:


          if (type in {typeVariable,typeParameter,typeFunction,typeMethod,typeField}) {...}

          И вообще то, за все время написания на ceylon мне ни разу не приходилось использовать === оператор. Я даже забыл что он есть :).


          1. lany
            07.06.2017 20:36
            +1

            Разумеется, вы заметили опечатку, перед вами же две строчки кода, а не проект из тысячи файлов, в одном из которых опечатка. Зачем же был введён ненужный оператор? :-) В дизайне языка самое главное — не решить, что в него добавлять, а решить, что в него добавлять не стоит. С этим, кстати, очень большая проблема у груви (@RockPresident привет). Грувисты всегда хвастаются тем, что у них есть, но не могут похвастаться тем, чего у них нету. Котлин гораздо лучше именно потому, что в нём меньше фич. И то несмотря на юный возраст Котлина, в нём уже есть лишние вещи.


    1. Cryvage
      07.06.2017 13:53
      +1

      Там же сказано, что сравниваются ссылки. Это два разных объекта в памяти.
      upd: немного опоздал.


      1. NikNik77771
        07.06.2017 13:56
        +1

        Кстати, т.к. Ceylon компилируется в JS его можно трактовать как очень мощно типизированный JavaScript.


        1. elmal
          07.06.2017 14:22

          Даже более того. Для JavaScript у Ceylon есть функционал Type Functions, в результате там с типами становится даже поинтереснее, чем на Java :).


      1. DenimTornado
        07.06.2017 14:02

        Понял, спасибо!


  1. OLDRihard
    07.06.2017 13:59
    +2

    А вот у меня вопросец. Я про этот яп узнал просто потому, что случайно набрел на него в сети. А почему он не выстрелил то? Он настолько страшный, что в него народ не пошел? Ей богу даже smalltalk чаще всплывает в инфополе чем этот яп.


    1. elmal
      07.06.2017 14:05

      Язык новый. На сам язык брошены ресурсы гораздо меньшие, чем на Kotlin. Раз так в 20 точно меньшие. Scala тоже очень долго не взлетала, а сейчас чуть ли не мейнстрим. В принципе только с начала этого года на Ceylon стало удовлетворительно писать используя IDEA. Eclipse ИМХО сильно на любителя. Посмотрим, может и выстрелить через определенное количество времени.


    1. foldr
      07.06.2017 19:13
      +1

      Вероятно, Red Hat не пиарят его так, как это делаю JetBrains, Google, Mozilla и Apple свои языки


  1. potan
    07.06.2017 14:08
    +2

    Аналог implicit там есть? В связи с развитием методологии Type Driven Development это важная фича.
    Вообще что в нем есть, чего нет в Scala?
    А вот необходимость писать return после Scala отпугивает.


    1. elmal
      07.06.2017 14:17

      implicit нет. Сознательно не стали делать, как и в Kotlin, чтобы не усложнять язык. В Kotlin и Ceylon есть хорошее решение проблем Null Safety. В результате чего нет необходимости использовать монады и усложнять код там, где можно без этого обойтись. Также в Ceylon гораздо лучшая система типов чем в практически любом языке, очень интересная типобезопасная рефлексия. Очень хорошие for comprehensions, практически как в Python и гораздо более читабельные, чем в scala. Очень хорошая поддержка Typles. И т.д, о чем отдельно. Собственно это первая часть статьи, где Ceylon выступал на поле Kotlin и оценивался по критериям Kotlin. Далее попробуем повоевать на поле Ceylon :)


      1. potan
        07.06.2017 15:00
        +3

        По мне так использование монад для Option удобно и позволяет писать общий код для разных контейнеров.
        А for в Ceylon c монадами работает (Future и тп)?


        1. elmal
          07.06.2017 15:20

          При необходимости можно использовать такие же приемы, как на Java 8 и Scala. Например вся асинхронность к меня завернута в rxJava. И далее всякие композиции, map, flatmap и и.д. Хотя, если честно, предпочел бы async await функциональность, которой пока нет — это ИМХО более читаемо.


          Если имеется в виду код:


          for {
             r1 <- future1
             r2 <- future2
             r3 <- future3
          } yield (r1+r2+r3)

          То на ceylon он бы выглядел как:


          value r = {
              for (r1 in future1)
              for (r2 in future2)
              for (r3 in future3)
              r1 + r2 + r3
          }

          Естественно это все нужно предварительно заврапить


          1. potan
            07.06.2017 15:30

            Я попробовал «async await», реализованный библиотекой в Scala и нашел эту функциональность ужасной, особенно когда пытаешся писать достаточно обобщенный код или работать со списками ассинхронных операций.
            for в Ceylon получает блок? Я могу написать аналог

            for {
             r1 <- future1
             r2 = r1+1
             r3 <- future3
            } yield {
             r2/r3
            }
            


            1. elmal
              07.06.2017 15:36
              +1

              На ceylon это будет примерно так:


              value r = {
                  for (r1 in future1)
                  let(r2 = r1 + 1)
                  for (r3 in future3)
                  r2 / r3
              }

              На деле это обычный for. Future в данном случае должна быть просто Iterable, просто возвращая одно значение. Для каждой итерации будет выполнен код, который идет после for. И далее это все обернется в ленивый Iterable. Если нужно не лениво, то вместо {for ...} будет [for ...] или можно {for ...}.sequence


              1. potan
                07.06.2017 16:14
                +1

                Хорошо.
                Только скобки в for и let смущают, как-то не ожидаешь, что описаные величины внутри скобок будут доступны в объемлющем блоке. С таким с только в макросах сталкивался.


                1. elmal
                  07.06.2017 16:17

                  На самом деле для такой задачи можно обычным map и flatMap обойтись, без всяких for, читаемость будет по крайней мере на ceylon больше. for comprehensions не совсем для этого нужен. Но если очень хочется — почему нет :)?


    1. elmal
      07.06.2017 14:33

      Кстати, в принципе можно обойтись и без return. Если мы пишем в функциональной парадигме, то можно воспользоваться => оператором вместо {}, в этом случае return не нужен. Во многих случаях это несколько ухудшает читаемость кода, приходится пользоваться оператором let и тому подобное, но возможно. В Kotlin кстати примерно такая же ситуация с return, как и в Ceylon.


      1. potan
        07.06.2017 14:58

        Собственно, одна из причин, почему Kotlin меня отталкивает.


    1. 0xd34df00d
      11.06.2017 01:25
      +1

      А зачем implicit нужен, кстати?


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


      1. senia
        11.06.2017 09:24
        +1

        Полного аналога на haskell скорее всего нет. Но, в частности, type class из haskell и trait из rust в scala — частный случай использования implicit.
        В частности в котлине не написать метод, аналогичный mempty из haskell, Monoid[T].empty из scala и Default::default() из rust.


        1. 0xd34df00d
          12.06.2017 23:15

          А в скале, оказывается, два implicit'а, implicit params и implicit classes. Речь идёт о втором, я так понимаю?


          1. senia
            12.06.2017 23:35
            +1

            Они связаны, но речь о первом. С точки зрения scala реализация для типа `T` type class `Monoid` — это требование наличия в текущем контексте implicit объекта/метода типа `Monoid[T]`. Отсюда, кстати, необычный для haskell эффект: в одной кодовой базе может быть 2 реализации одного type class, например если вам требуется 2 разных маршалинга в JSON для ваших типов (1 в БД, другой — в REST), вы можете написать/получить макросами 2 реализации `Format[T]` и в месте использования импортировать нужную. Отсюда же не очевидное неудобство, от которого сейчас избавляются в Dotty.

            На самом деле «implicit classes» — это частный случай к implicit conversion. И по сути это ближе всего к extension methods, но с тем важным отличием, что возможно не только добавление отдельных методов, но и приведение к интерфейсам.

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


            1. 0xd34df00d
              13.06.2017 18:51
              +2

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


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


      1. elmal
        11.06.2017 09:30

        Как минимум это полезно при написании DSL. На Scala можно написать очень навороченные DSL практически любого синтаксиса. В этой области Scala рулит и рулит просто неимоверно. На Kotlin возможностей по написанию DSL будет поменьше, некоторых вещей будет не хватать. На Ceylon ситуация хуже, чем у Kotlin. За счет обязательной точки с запятой и из за того, что вызов функции всегда идет с указанием скобочек, и нельзя аргументы передавать через пробел. Но намного намного лучше, чем на Java.


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


      1. senia
        11.06.2017 09:32

        Но если хотите объяснения что такое implicit, то лучше послушать Одерски: What to Leave Implicit. Только учтите, что все такие доклады больше рассчитаны на людей из java, а не из haskrll.


  1. igormich88
    07.06.2017 15:16
    +1

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

    case(is String)
    
    не превращается ли switch просто в более красивую запись дерева условий?


    1. elmal
      07.06.2017 15:30
      +2

      Со switch там интереснее. Как это под капотом, по существу не важно, это 100 раз могут безболезненно поменять


      У switch там совсем другое назначение по сравнению c Java. Именно в Java я его практически не использую, кстати, ибо вероятность что я там ошибусь и поставлю break достаточно высока.


      Предположим у меня тип


      Integer|Exception i = Integer.parse("56);

      Или же что поинтереснее:


      Integer|Exception|Complex p = doComplexParsing("345|45");

      Если я делаю switch(p)
      То сама IDE заставит меня и сгенерирует код для обработки всех возможных вариантов p
      То есть


      case(is Integer) {}
      case(is Exception) {}
      case(is Complex) {}

      И если какого case не будет или не будет else, то ругнется компилятор, что я не все возможные значения отработал. За счет чего использование switch в Ceylon очень даже приветствуется.


      Ну и также когда switch используется совместно с tuple, entry и деструктуризацией — получается весьма неплохой код, почти паттерн матчинг.


    1. potan
      07.06.2017 16:17
      +1

      Если я правильно понял, там полноценный pattern matching.
      Ну и то, что это выражение, а не оператор, удобно.


      1. elmal
        07.06.2017 16:25
        +1

        К сожалению нет.


        Для полноценного хотелось бы:


        case(Person("Vasja", 33)) { print("this is Vasja 33")} //не поддерживается
        case(Animal(name)) {print(name);} //не поддерживается
        case(["56", a]) {print(a)}; //не поддерживается,придется делать case([String str, Object a]) {if (str == "56") {print(a)}};


        1. potan
          07.06.2017 16:35
          +2

          Странно. Как без этого можно жить?


          1. elmal
            07.06.2017 16:52
            +1

            Жить можно без чего угодно. На Java нет даже близко ничего подобного, и народ как то не жалуется. Ибо про альтернативы не знает. Частые use case язык покрывает, остальное возможно появится в будущем. На практике очень часто используются кортежи и их деструктуризация, соответственно для значительной части задач этого хватает.


            1. potan
              07.06.2017 17:13
              +2

              С современной поддержкой IDE удобно заводить case class/data class на каждый чих. Кортежи как-то снижают преимущество от статической типизации.


              1. elmal
                07.06.2017 17:25

                Если бы были эти case class/data class. Но вообще, обещают алиасы класса на кортеж, но скорее всего будет не в этом релизе. Соответственно будет достаточно статически типизованно. Будет почти data class.
                Надо понимать, что Ceylon это не Scala и не Kotlin. У него свои бест практики.


            1. sshikov
              07.06.2017 21:14

              Насчет близко — это вопрос немного субъективный. Вы javaslang видели?


              1. elmal
                07.06.2017 21:52

                Так это же библиотеки, а не сам язык. За счет библиотек можно сделать ОЧЕНЬ многое на любом языке. Вот только библиотеки — это не забыть добавить зависимости, не забыть про статик импорты, выглядит это чужеродно, большинство разработчиков про такое не знают ибо не всегда распространено, в конкретной конторе такую библиотеку могут вообще запретить к применению ибо каждую внешнюю либу нужно согласовывать в 10 инстанциях и т.д. Нужно следить за версиями библиотек и их зависимостями и тому подобное. Можно все, на любом языке. Хотя бы кодогенерацией :). Вопрос в лишних телодвижениях. В свое время я делал эти телодвижения и считал, что Java прекрасна ибо на ней можно все. А потом попробовал альтернативы, когда много полезного уже есть из коробки. И обратно то уже не хочется ...


                1. sshikov
                  07.06.2017 22:06

                  Я прекрасно понимаю, что это библиотека. Я в общем-то просто прокомментировал вот эту фразу:

                  >На Java нет даже близко ничего подобного

                  Это все-таки не совсем верно. Есть многое, хотя и не совсем таким же образом реализованное. Тот же ломбок, к примеру.

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

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


                  1. elmal
                    07.06.2017 22:22

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


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


                    1. sshikov
                      07.06.2017 22:27

                      Я вполне себе помню и применял functionaljava, guava (и еще пару аналогов). Но эстетически это порой было ужасно, а не прекрасно.

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


                    1. lany
                      08.06.2017 03:53

                      Ага, можно ещё Advanced Code Folding поставить, вообще другой язык будет :-)


        1. guai
          08.06.2017 14:43
          +1

          А по-моему, правильно и не сделали.

          Вот 33 — это у нас что?
          int, long, short, byte? double еще матчим или уже нет?
          А если это явавский объект с несколькими конструкторами?

          Кучу странных способов угадывания вкомпиливать в каждый кейс — это был бы overloading 2.0, от одного только что избавились :)


          1. rraderio
            09.06.2017 11:29
            +1

            Вот 33 — это у нас что?

            Это int, также как в Java 33 это int а не long, short, byte, float, double


            1. guai
              09.06.2017 13:21

              pattern matching — отстой.
              Это способ причесать антипаттерн, когда куча ветвлений делается по динамическому типу и значению.
              Либо он будет ограничен небольшим набором системных типов, либо там такая каша из правил будет, что никто ее никогда не запомнит, и не будет понимать, а что конкретно будет и что не будет матчиться в том или ином случае.
              Вот в данном случае Person(«Vasja», 33) — какие объекты матчим, какие нет? 33 вообще с каким полем сравниваем? По синтаксису похоже на параметр конструктора. А где мы его возьмём? Мы могли вообще никак не запоминать это значение, а параметр как-то заюзать в самом конструкторе, например. Или он приватный, рефлекшены подключать?
              Допустим, как-то поняли, с чем сравнивать цифру. И что хотим именно int или Integer со значением 33.
              Со строкой не меньше непоняток. Строка явы — наверное да, строка цейлона — тоже. Массив char'ов? Объект с toString()? StringBuilder/StringBuffer? Своя кастомная коллекция с char'ами? Учитываем регистр? Допустим, да. Как тогда описать матчинг, чтобы нет? Comparable#compare(«Vasja») == 0 — ?
              Наследников Person матчим? А если у них другие конструкторы? А если мы еще и при компиляции не знаем, у кого какие? Опять рефлекшены? Прощай performance :(
              Как переопределять матчинг для своего класса?
              Плюс все радости оверлоадинга, когда код может внезапно без палева начать работать по-другому, потому что ты определил более специфичный метод/конструктор.


              1. 0xd34df00d
                11.06.2017 01:28
                +1

                Не антипаттерн это (в общем случае). Посмотрите, как оно в хаскеле и товарищах сделано, никакой каши правил, все ясно и понятно, даже если всякими view patterns и pattern synonyms обмазываться.


                1. guai
                  11.06.2017 01:50

                  ну в хаскеле и нет такой каши из классов и интерфейсов
                  и уж тем более там нет надобности интероп с явой поддерживать :)


              1. rraderio
                12.06.2017 14:45

                от в данном случае Person(«Vasja», 33)

                Должен быть конструктор который принимает String и int.

                call("Vasja", 33)
                

                Откуда вы знаете какой метод будет вызван? Который принимает массив char'ов? Объект с toString()? StringBuilder/StringBuffer? Своя кастомная коллекция с char'ами?


                1. guai
                  12.06.2017 15:20

                  я и не знаю в общем случае. String, CharSequence, Integer, int, Object в разных комбинациях могут быть. еще вариадик может быть.
                  поэтому оверлоадинг — отстой.
                  и поэтому его в цейлоне нет.
                  возвращать его второй раз в виде паттерн-матчинга — тоже отстой и тоже не стали так делать, за это я разрабов языка уважаю и прям расцеловал бы при случае :)


                  1. rraderio
                    12.06.2017 15:35

                    поэтому оверлоадинг — отстой

                    Т.е. вы называете методы callStringAndInt?


                    1. elmal
                      12.06.2017 16:16

                      На самом деле без оверлоадинга в Ceylon можно жить достаточно комфортно. Во первых, оверлоадинг при необходимости делается через Union Types. Метод один, он принимает определенные аргументы, а аргумент может быть или одного типа, или другого. А далее в обработчике либо сразу учитывать логику, либо уже делегировать специфичным непубличным методам. Во вторых, в Java большинство оверлоадинг методов нужны, так как там нет параметров по умолчанию. В третьих, если уж ну совсем приспичило с оверлоадингом, что ну никак не исхитриться (мне не доводилось с таким сталкиваться, но мало ли), то никто не запрещает написать нужную логику на Java, и вызывать этот оверлоадинг из Ceylon.


                      1. rraderio
                        12.06.2017 16:33

                        оверлоадинг при необходимости делается через Union Types

                        Т.е. вместо того чтобы в compile-time знать какой метод надо вызывать, мы теперь будем в run-time определять?
                        Во вторых, в Java большинство оверлоадинг методов нужны, так как там нет параметров по умолчанию.

                        Так ведь тогда и конструктор будет один и не будет неоднозначностей


                        1. elmal
                          12.06.2017 16:43

                          Да, в рантайме. Да, перфоманс. Но про перфоманс я уже ответил.


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


                          https://objectteams.wordpress.com/2017/04/02/several-languages-java-8/


                    1. guai
                      12.06.2017 16:25

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


                      1. rraderio
                        12.06.2017 16:40

                        Ну так и конструктор можно

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

                        и у вас обычно будет только один конструктор, так что неоднозначностей не будет


                        1. guai
                          12.06.2017 19:18

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


              1. rraderio
                13.06.2017 09:11

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

                Вы пишите тесты? И как часто вы определяете более специфичный метод/конструктор?


                1. guai
                  13.06.2017 11:45

                  А это тут при чем?
                  Любой косяк языка можно подоткнуть административными костылями, бестпрактисами, стайлгайдами, тестами, тулзами, чекерами и т.п. На качество языка это влияет разве лишь косвенно.
                  Разрабы цейлона утверждают, что у него такое же свойство, как у хаскеля, образовалось: 95% написанного кода работают сразу, как удовлетворил компилятор еще до запуска. Ну и мой опыт пока этому не противоречит.


                  1. rraderio
                    13.06.2017 17:16

                    А это тут при чем?

                    образовалось: 95% написанного кода работают сразу, как удовлетворил компилятор еще до запуска

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


                    1. guai
                      13.06.2017 17:47

                      «читабельный» и «понимабельный» — разные вещи.
                      эти подкапотные правила надо в голове применить, чтоб понять, что происходит.
                      и если в языке не полтора типа данных, как в лиспе, правила не будут простыми.


                    1. 0xd34df00d
                      13.06.2017 18:46
                      +3

                      Вы все ровно пишите тесты и можете проверить какой метод вызвался.

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


                      95% вместо 100% потому, что есть логические ошибки, связанные тупо с неправильно построенным алгоритмом.


                      1. rraderio
                        13.06.2017 23:09

                        Как тайпчекер и свойства языка могут гарантировать что например вызвался метод отправвки эмейла при регистрации?


  1. rraderio
    07.06.2017 16:21
    +4

    Интерполяция строк
    Это как бы более умная и читабельная версия String.format() из Java, встроенная в язык:
    value x = 4;
    value y = 7;
    print("sum of ``x`` and ``y`` is ``x + y``"); // sum of 4 and 7 is 11
    


    ИМХО синтаксис здесь будет поприятнее, чем в Kotlin, с Java даже не хочется сравнивать.

    Kotlin
    val x = 4
    val y = 7
    print("sum of $x and $y is ${x + y}") // sum of 4 and 7 is 11
    

    и что вам тут не нравиться?


    1. elmal
      07.06.2017 16:28

      Знак ${}.
      Приведу цитату из FAQ непосредственно от разработчиков языка https://ceylon-lang.org/documentation/1.3/faq/language-design/#string_interpolation_syntax:


      Why not "Hello $name" or "Hello ${name.uppercased}"?

      Primarily because it looks a bit cleaner for defining text in user interfaces or other treelike structures.


      Html hello {
          Head head { title="Greeting"; }
          Body body {
              P { "Hello ``name``. Welcome back!" }
          }
      }

      We did originally investigate the ${...} syntax, but it turns out that syntax would require a stateful lexer and, since } is a legal token in the language, is more fragile when editing code in an IDE. Anyway, some of us just don't love seeing dollar signs all over the place. It reminds us of languages we don't like.


      1. rraderio
        07.06.2017 16:47
        +1

        Anyway, some of us just don't love seeing dollar signs all over the place. It reminds us of languages we don't like.

        Т.е. не нравится Java, но синтаксис уноследовали, а знак доллара не нравится, его не взяли.


        1. elmal
          07.06.2017 17:06

          Синтаксис Java унаследован частично. Например не public, а shared, не implements а satisfies и т.д. Из Java в основном идет имя типа слева от переменной, ключевой слово class и фигурные скобочки. Сам язык просто создавался с нуля, с учетом того хорошего, что было до этого.


        1. guai
          09.06.2017 12:15
          +1

          It reminds us of languages we don't like.

          тут явно не яву имели в виду :)


      1. sshikov
        07.06.2017 22:08
        +2

        Вопрос спорный. И явно личные предпочтения тут перевесили.

        P.S. Мне тоже `` напоминает кое-что из того, что хотелось бы забыть.


      1. 0xd34df00d
        11.06.2017 01:30

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


        1. rraderio
          12.06.2017 16:16

          Чем это лучше?


          1. 0xd34df00d
            12.06.2017 23:32
            +1

            1. Упрощает ядро языка.
            2. Позволяет реализовать разные варианты, хоть с долларами, хоть с #{expr}, хоть с backtick'ами.
            3. Позволяет реализовывать всякие другие нереализованные в ядре языка вещи, вроде типобезопасного printf с проверкой строки формата в компил-тайме.
            4. Даёт чуть большую уверенность, что язык в известном смысле правильно спроектирован, если в нём такие вещи выражаются достаточно просто.


            1. rraderio
              13.06.2017 09:03
              -1

              Позволяет реализовать разные варианты, хоть с долларами, хоть с #{expr}, хоть с backtick'ами.

              Это скорее минус, если каждый будет делать как он хочет.

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


  1. vba
    07.06.2017 16:23
    +2

    Хочу рассказать о новом языке программирования, который называется Ceylon

    Kotlin не вчера появился, но Ceylon по моему, старше Kotlin-а лет так на 5 или 6, у него первый стабильный релиз был в 2011, когда Kotlin только только зарождался.


    1. kefirfromperm
      07.06.2017 16:56

      Котлин до 1й стабильной версии шел долго. А у цейлона поддержки в идее не было.


  1. rraderio
    07.06.2017 16:32

    В отличие от Kotlin обошлось без ключевого слова downTo.

    value n = 10;
    value m = 2;
    
    for (i in n..m) { ... }  
    

    Ceylon в рантайме делает проверки?


    1. elmal
      07.06.2017 16:44

      n..m это просто синтаксический сахар для Range.


      Внутри код вроде:


          shared actual 
          Element[] span(Integer from, Integer to) {
              if (from <= to) {


      1. rraderio
        07.06.2017 16:52

        if (from <= to) {

        Т.е. каждый раз проверяется в рантайме :(

        А если нам надо чтобы цикл выполнялся только если n < m?


        1. elmal
          07.06.2017 17:13

          На выбор:


          for(n in 0..m) {...}
          for(n in minInteger..m) {...}
          for(n in spanTo(m)) {...}


          1. rraderio
            07.06.2017 17:19

            Эээ, у меня функция принимает n и m

            void count(Integer n, Integer m) {
                for (i in n..m) {
                     print(i);
                }
            }
            

            так вот, мне надо чтобы метод print исполнялся только если n < m


            1. elmal
              07.06.2017 17:29

              if (n >= m) { return; } // причем на практике скорее всего будет assert(n<m);
              
              for (i in n..m) {
                  print(i);
              }


              1. rraderio
                07.06.2017 17:35
                +1

                Уж лучше с downTo. Кстати это не ключевое слово.


  1. elmal
    07.06.2017 16:41
    +3

    И тот и другой 2011. По сравнению со Scala, которая в 2003 появилась. Scala стала мейнстримом где то последние года 4, по крайней мере на scala можно найти работу без проблем. Kotlin стал настолько популярен, что на нем можно найти работу — тоже только в последние несколько лет. Но на Ceylon тоже можно работу найти, у меня получилось, когда я искал работу на Scala или Kotlin :):):).


    Что считать стабильным релизом на самом деле еще и вопрос. Первая стабильная версия 1.0.0 в 2013 году. В гораздо более стабильном языке я лично зарепортил весьма немало багов, некоторые даже сам и поправил :).


  1. RockPresident
    07.06.2017 17:48
    +2

    Читаю все эти статьи и не пропадает впечатление что авторы просто не слышали о языке Groovy? В котором всё это уже есть лет 10, да плюс ещё огромное количество настолько же полезных возможностей. Стабильный язык, почти полная совместимость с .java кодом (и причём не такая где можно использовать другие java библиотеки, а в том смысле что можно просто взять .java файл, и он скомпилируется groovy сразу), полное решение всех verbosity проблем которые есть у джавы, куча паттернов позволяющих быстро прототипировать и вообще писать код, хорошая читаемость, узнаваемость, convention over configuration, свободный выбор между static type compilation/dynamic type compilation, (причём на уровне отдельных классов или даже методов!) и так далее.


    Автор, если вы не пробовали Groovy, обязательно сделайте это.


    1. NikNik77771
      07.06.2017 18:16

      Присоединюсь к пожеланиям статьи о преимуществах по сравнению с Groovy, т.к. когда делали Ceylon Groovy уже был и Гэвин Кинг об этом знал. Значит Groovy чем то не устраивал.


      1. fzn7
        07.06.2017 19:48

        NIH синдром как он есть


      1. AlexTheLost
        07.06.2017 21:46
        +1

        Ещё была Scala.)


    1. sshikov
      07.06.2017 22:12

      Знаете, я в прошлой статье про котлин прокомментировал в том же духе — так мне минусов понаставили. Причем аргументировали один раз — что производительность groovy плохая (а подтвердить при этом ничем не удосужились). А по сути тут вопрос ровно тот же встает — а чем это лучше groovy? Который не просто появился давно, но и распространен весьма широко (как сам по себе, так и в виде gradle например, и не только), и большую часть ровно этих же преимуществ имеет (ну кроме компиляции в JS, пожалуй).


      1. elmal
        07.06.2017 22:42
        +2

        Либо его недостаточно пиарили. Либо я что то пропустил:
        1) Как у groovy с иммутабельностью по умолчанию?
        2) Как там дела с for comprehensions?
        3) как там дела с деструктуризацией кортежей, причем чтоб деструктуризация была прямо в лямбдах?
        4) Как там с женериками? Можно ли в groovy у List узнать в рантайме тип T?


        1. sshikov
          07.06.2017 22:55

          Вы пропустили gradle? Серьезно? А в остальном — да, это некоторые из реальных недостатков (ну, их можно считать такими).

          1. По умолчаню — никак. А вообще примерно как в Java, можно написать аннотацию Immutable, т.е. по сути — на уровне обработки AST где-то достигается. Встроено в язык.
          2. В принципе. средства расширения языка (включая и лямбды сюда же) вполне позволяют например написать свой цикл until, имея только лямбды. Не задумывался об этом, но подозреваю, что можно сделать вполне пригодное что-то.
          3. Простой запрос гуглю отвечает ссылкой http://groovy-lang.org/semantics.html#_object_destructuring_with_multiple_assignment, которая показывает, что это тоже одна из возможностей расширения языка. Т.е. есть multi assignment, и можно кое-какие методы объекту дописать, чтобы он деструктурировался. Не блестяще наверное, но напомню — этому языку уже лет 10.
          4. По-моему также, как в Java. Тип T можно узнать, он сохраняется в байткоде, но скажем так — не слишком прямолинейно это делается. Я подозреваю, большинство программистов про этот способ не слышали. TypeToken например погуглите, это из guava. Type erasure тут сильно мешает, и язык мало что может с этим сделать (разве что нарушив совместимость с Java на уровне байткода, что мы видим на примере скалы).


          1. RockPresident
            08.06.2017 01:49

            Писать аннотацию Immutable самому даже не нужно, она уже есть: http://docs.groovy-lang.org/2.4.7/html/gapi/groovy/transform/Immutable.html


            1. sshikov
              08.06.2017 12:31

              Я когда писал «встроено в язык» именно это и имел в виду — аннотация уже есть, ее логику делать не нужно.


      1. RockPresident
        08.06.2017 01:45
        +1

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


    1. AnyKey80lvl
      07.06.2017 22:34
      +1

      Обожаю Groovy! По-моему, недооцененный язык.

      Но всё-таки хочется уточнить:
      можно просто взять .java файл, и он скомпилируется groovy сразу

      Это true только для java-файла до 1.7 включительно. Лямбды из 1.8, например, не скомпилируются.


      1. sshikov
        07.06.2017 22:56

        Да. Поддержка 1.8 вроде ожидается. Когда будет — непонятно.


  1. mr-garrick
    07.06.2017 19:12

    С нетерпением жду подобную статью про Groovy, Jython и т.п. :)


    1. sshikov
      08.06.2017 12:36

      С Jython все не так красиво. Насколько я понимаю, язык застрял на уровне версии 2.x. И версии 3.x похоже не будет никогда.


      1. mr-garrick
        08.06.2017 14:40

        Да, но и сам Python 2 ещё вполне востребован и похоже будет востребован ещё долго.


        1. sshikov
          08.06.2017 14:54

          Ну, если вас 2 устраивает, то версия 2.7 есть, в этом плане все более-менее хорошо. А с учетом того, что доступна вся инфраструктура Java, я бы даже сказал, что очень хорошо. Для некоторых задач. Я когда-то применял внутри Weblogic — и остался более чем доволен.


        1. foldr
          08.06.2017 17:33

          Уже не долго. Срок поддержки заканчивается в 2020 году. Django, ipython больше не поддерживают 2 ветку. В Heroku теперь версия по умолчанию — 3.6


  1. Sirikid
    07.06.2017 21:24
    +2

    Также, как и Kotlin, как и Scala, Ceylon на 100 % совместим с Java. Можно без проблем вызывать из Java Ceylon код, также без проблем вызывается Java код.

    И Scala, и, как оказалось, Kotlin не на 100% совместимы с Java, ваши комментарии по этому поводу?


    Диапазоны

    Почему столько вариантов и чем они друг от друга отличаются? (Кроме очевидного by.)


    Имхо
    Выражение switch

    Очень многословнное и отформатировано совсем уж отвратно.


    1. AlexTheLost
      07.06.2017 21:49

      Что вы имеете ввиду? Насколько мне известно любой Java код можно вызвать из Scala, наоборот нет и это очевидно.) Scala более богатый на возможности язык чем Java.


      1. elmal
        07.06.2017 21:57
        -1

        Наоборот тоже прекрасно вызывается. Через одно место, громоздко, криво, но вызывается :).


      1. Sirikid
        07.06.2017 21:59
        +1

        Обычно (в контексте обсуждения языков для JVM) под 100% совместимостью понимается полный интероп в обе стороны.


      1. elmal
        07.06.2017 22:33
        +1

        Наоборот нет? Я помнится извращался, и вызывал Scala код не только из Java, но и из Ceylon.


        1. senia
          07.06.2017 22:37

          Это возможно в очень многих случаях, но есть исключения. Самое явное — макросы.


    1. elmal
      07.06.2017 22:14

      И Scala, и, как оказалось, Kotlin не на 100% совместимы с Java, ваши комментарии по этому поводу?

      C Java как языком, или с некоторыми Java библиотеками и некоторыми тяжелыми серверами :)? Именно с взаимодействием с Java проблем нет. Как в одну, так и в другую сторону. Например я люблю в IDEA в момент точки останова делать evaluate expression, и вызывать непосредственно нужный метод. Я это любил делать в Java — я продолжаю таким заниматьсяи в Ceylon, хоть и мне приходится знать как ко всему этому достучаться из Java. Возможно с выходом Java 9 на начальном этапе будут какие то мелкие проблемы, а может и крупные, пока нормальной поддержки Java 9 не появится в языке. До версии Ceylon 1.3.0 были мелкие проблемы с взаимодействием с Java 8, но тоже вполне решаемые.


      Почему столько вариантов и чем они друг от друга отличаются? (Кроме очевидного by.)

      Включая, не включая, в обратном порядке, c шагом, проверка на нахождение в диапазон в if. Там можно и поболее вариантов привести.


      И самый главный вопрос, почему же стоит переходить на Ceylon или Kotlin?

      Про это будет далее. Если коротко в этих языках исправлены фундаментальные недостатки Java. А именно — многословность, мутабельность по умолчанию, проблема c null safety. Весьма поднимает это все производительность разработки.


      1. Sirikid
        07.06.2017 22:54
        +1

        Как с языком. Например как использовать из Java овеществленные дженерики?
        Об этом стоило написать в посте.
        И об этом тоже.


        1. elmal
          07.06.2017 23:22

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


          1. Sirikid
            07.06.2017 23:40
            +1

            Тогда глупо говорить про 100% совместимость.


            1. NikNik77771
              08.06.2017 14:46

              А как вы себе 100% совместимость представляете, если в java ее нет?


              1. voddan
                10.06.2017 10:06
                +1

                В Kotlin выкинули овеществленные дженерики чтобы со стороны Java код выглядел нормально. Без этой жертвы странно говорит про 100% или даже 99% совместимость с Java.


                1. elmal
                  10.06.2017 12:54

                  Я немного не понимаю какие тут большие проблемы. Вот код использования из Java ceylon ArrayList вместе с цейлоновскими же строками:


                  ceylon.collection.ArrayList<ceylon.language.String> ceylonStrArr = new ceylon.collection.ArrayList<ceylon.language.String>(ceylon.language.String.$TypeDescriptor$);
                  ceylonStrArr.add(ceylon.language.String.instance("I am adding ceylon string from Java"));

                  Специально не убирал явные имена пакетов, из за чего здесь это выглядит громоздко. Все проблема с овеществленными женериками из Java некрасивый $TypeDescriptor$ в конструкторе.


                  1. elmal
                    10.06.2017 13:03

                    Единственная практическая проблема с вызовом из Java кода кода на Ceylon заключается в IDE. IDE да, пока не видит из Java цейлоновские классы. Из за чего внутри среды разработки Java код, вызывающий Ceylon код выглядит красным. Но это компилируется и запускается. И эта проблема актуально только в том случае, если проект изначально цейлоновский, и я мешаю там вызовы из Java в Ceylon. Если же цеплять jar, написанный на Ceylon к уже существующему проекту, то таких проблем не будет. Но рано или поздно это пофиксят, соответствующая бага давно заведена.


                  1. voddan
                    10.06.2017 17:16
                    +1

                    API где нужно всюду передавать $TypeDescriptor$ не назовешь идиоматичным Java кодом.


                    Я хотел еще раз подчеркнуть что в Kotlin трактовке "совместимость в обе стороны" подразумевает идиоматичный вид Java из Kotlin и Kotlin из Java. Мне кажется этот очень важный факт принижается в статье с отмашкой "где мы такое не видели".


    1. senia
      07.06.2017 22:35

      Навскидку (с цейлоном у меня даже хуже, чем с котлином): Цейлон позволяет отличить MyClass<Integer> от MyClass<String> в case. Достигается за счет доп. информации в инстансах дженериков. Сломается если MyClass<T> создан в java. Как это взаимодействует с джавовыми либами, создающими экземпляре на основе рефлексии (маршалинг, БД, etc), я затрудняюсь предугадать.


  1. p9202583853
    08.06.2017 07:09
    -1

    я не профи, но какая разница? Ceylon… Kotlin… все конструкции очень похожи друг на друга
    наверное заминусуют сейчас люто, но!
    вы видели современный swift? Там все тоже самое, различия минимальны


    1. elmal
      08.06.2017 07:27

      Ceylon, Kotlin, Scala — это JVM языки. JVM инфраструктура реально огромна, уже для Java написано огромное количество прекрасных библиотек и фреймворков. На Ceylon я могу, например, взять HazelCast, и писать линейно масштабируемое облачное распределенное ПО. Получив распределенные лямбды, распределенные локи, распределенные кеши, распределенные экзекуторы и т.д. И я не просто могу теоретически, я это делал практически. Продолжить писать код, выглядящий как работающий на одной машине, но де факто исполняющийся на кластере из тысячи серверов. Я могу взять vertx, и получить распределенный асинхронный фреймворк, который без проблем кластеризуется и требует минимум настройки. Я могу взять akka, и писать в парадигме акторов, не бояться дедлоков и вообще думать не о потоках, а о бизнес логике. Я могу взять rxJava, reacive streams, и работать с асинхронным кодом практически как с синхронным. Java инфраструктура очень хороша для бекнда и серверной разработки. Kotlin сейчас весьма популярен во фронтэнде за счет поддержки Android. Ceylon в принципе для этого тоже можно использовать, но мои задачи от фронтэнда далеко, потому насколько он хорош, я сказать не могу. Можете кстати посмотреть недавное выступление Gavin King где он рассказывает как он переписывал тестовый Android проект с Java на Ceylon. https://www.youtube.com/watch?v=zBtSimUYALU


  1. vlanko
    08.06.2017 09:02
    +2

    Популярность вакансий у нас, относительно Java:
    Scala — 11%
    Groovy — 7.4% (тестировщики :)
    Kotlin — 1.7% — просто Java с доп. требованиями Котлина.
    Ceylon — 0


    1. guai
      08.06.2017 12:35
      +1

      Яве 22 года, скале 13 лет, цейлону с котлиным примерно по 5, от первого релиза, заявленного стабильным, что-то в районе полутора, вроде бы.
      JB уже начали активный маркетинг не выдав толком релиз, RH еще ждут, полируют до сих пор, всё таки RH нацелен на кровавый интерпрайз, где лучше перебдеть.


    1. elmal
      09.06.2017 13:01

      Ceylon не 0. А в настоящее время минимум 1 вакансия, а то и вообще 3. В вакансии только нет ни слова про Ceylon, там Java стоит, кандидатов шокируют позднее :). Актуально для Питера, деньги не суперские, но и не совсем доширак, если кому интересно — можно в личку стучаться.


  1. guai
    08.06.2017 13:41
    +2

    Смысла переводить готовый большой проект на котлин я не вижу, а вот на цейлон — вижу.
    Если уж заморачиваться, то хочется фичей по максимуму, прям чтоб с запасом :)
    А проделать много работы и получить примерно то же самое, но с сахарком — по-моему, не стоит того.
    С цейлоном сразу имеем и модульность и овеществленные дженерики, и систему типов, которую в скале только делают еще, и кмк скорее приведут этим к расслоению скалы на 2 версии, как с питоном произошло.
    ДСЛ из коробки для всего, вообще без никакого обвязочного кода.
    Про стопроцентную совместимость уже писали, что ее нет и быть не может.
    Так вот, в цейлоне и не заявляют, что она есть, там предлагают наделать на нужные явавские либы модулей-оберток, минимизировать границу соприкосновения, и дальше остальное пилить на цейлоне. И это не сильно сложно. Скала доказала, что так жить можно.
    В котлине замахнулись на более тесный интероп с явой, так, чтобы четкой границы вообще не было. И имхо это у них не выгорело, сами же пожертвовали null-safety на границе в угоду более казуальному процессу написания кода.
    Цейлон целенаправленно фиксит косяки явы, а не просто добавляет сахарку, и не улетает в эмпиреи.


  1. pioneer
    08.06.2017 16:44

    Эх, не хватает async/await.


  1. voddan
    10.06.2017 10:18

    Как работают стандартные коллекции в Ceylon? Они "свои" или используются классы из JDK? Если я использую совместимость с Java, придется ли мне копировать (даже если и неявно) из коллекции в коллекцию?


    1. elmal
      10.06.2017 12:10

      Коллекции свои, написанные с нуля. Если совмещать Java и Ceylon коллекции — да, придется копировать. Синтаксис работы с Java коллекциями достаточно прозрачный и в принципе с Java коллекциями можно довольно комфортно работать. В основном на практике использую Java коллекции, когда мне нужно parallelStream использовать или если использую Java библиотеку. По умолчанию чаще всего стараюсь использовать не List, а Sequence или Iterable, а коллекции только когда реально необходимо. Ибо синтаксис Sequence и Iterable ИМХО гораздо чище. Если коллекции реально нужны, приоритет отдаю цейлоновским, если нельзя (например мне нужны коллекции из пакета Concurrent, а у цейлона на уровне языка поддержки многопоточности нет вообще) — используем Java коллекции. Один разок я даже Scala коллекции решил заюзать, завелось без проблем.


      1. voddan
        10.06.2017 17:24

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


        Я понимаю что в этой статье вы не ставили себе задачу сравнить все за и против, но вообще это был бы один из минусов Ceylon.


        1. elmal
          10.06.2017 18:58
          +1

          На самом деле, когда реально важна производительность, там вообще не до коллекций :). Уже и на Java узким местом становится боксинг анбоксинг и тому подобные приколы, потому может потребоваться отказаться от Java коллекций в сторону обычных массивов примитивов. Как в одном из наших проектов на Ceylon, на каждый уникальный запрос перелопачивали в памяти 500 миллионов записей с фильтрацией группировкой аггрегацией на кластере :). Пришлось посидеть с профайлером и ускорить удалось где то в 60 раз. Узкие места были переписаны на Java. Но именно взаимодействие Java кода с Ceylon кодом для наших задач никогда не была узким местом. В настоящее время узкое место — скорость DoubleAccumulator. Предполагаю можно еще процентов на 30 поднять, и возможно еще раза в 2-3, если использовать кодогенерацию в Java и использование JavaCompilerAPI ради разворачивания циклов, но уже скорости хватает. И так практически в шину памяти удалось упереться, за 3 секунды перелопатить 30 гигов на каждой ноде это не так чтобы и медленно. Если бы проект писался целиком на Java, а не на Ceylon — быстрее бы точно не было. А так, переписать на Java пришлось процентов 10 кода. После профилирования. И даже если б писалось это изначально на Java — пришлось бы узкие места точно так же переписывать.


          Производительность это совершенно отдельная тема, но по опыту использования — с производительностью у Ceylon достаточно неплохо. И взаимодействие с Java в тех узких местах, где код желательно было переписать на Java в нашем случае проблемой не стал.


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


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