Pull to refresh
10
0
Михаил Малютин@elmal

Разработка ПО

Send message
22# Конструирование коллекций (for comprehensions)
Многомерное итерирование поддерживатеся?

Эквивалентный код:


    value res = {for (x in (1:15).by(2)) 
                 if (x % 3 == 0) 
                 for (y in (1:10).by(3)) x -> y}

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


24# Метамодель
Звучит очень хорошо. Это полноценный механизм макросов как в scala? Можно при помощи него генерировать новые классы во время компиляции?

Нет, даже близко не макросы. Ceylon не поддерживает вообще никакого Compile time метапрограммирования. Только рантайм. На самом деле я сделал в одном проекте кодогенерацию на основе метамодели, но это близко к костылю так как метод кодогенерации я должен сначала скомпилировать, потом дернуть, затем скомпилировать результат.


24# Улучшенные дженерики
Вообще хорошо, но нельзя забывать, что это влечет некоторые проблемы при взаимодействии с java. Например с java библиотеками для сериализации в JSON.

На самом деле в основном тут с большим потреблением памяти. Когда в коллекции с дженериками потребовалось пихать миллиарды значений, это съело примерно в 2 раза больше памяти чем на Java коллекциях. Потому пришлось быстренько эти места переписать на Java. Кстати, именно с библиотеками для сериализации именно с улучшенными дженериками проблем то и нет :). Там в самом языке есть хинт — ee режим. Если нужно сериализовать классы, и они помечены определенными аннотациями, соответствующая коллекция будет для Java библиотеки выгляжеть как Java коллекция, и сериализация пройдет. С сериализацией есть действительно проблемы, но в принципе жить можно. Самая очевидная — иерархические класслоадеры. Сериализовать без проблем. А десериализовать — проблема, так как класслоадер библиотеки сериализации не видит классы, вызывающие эту библиотеку. Но есть хинт, ключ --flat-classpath, в результате чего класслоадер будет один и поведение как в Java/


25 Общий дизайн языка

Естественно дискуссионный. На самом деле Scala весьма и весьма крута, и это я постараюсь отразить в следующей статье, наброски которой у меня уже есть. По фичам для написания DSL со Scala тягаться весьма проблематично. Но к Scala нужно привыкать. Ceylon вполне читабелен даже без привыкания.

Нет, информация о типе не сохранится.


{String+} mapped = [1, 1.0, "2.3"].map((Integer|Float|String element) => element.string);

Результат Map — всегда Iterable. Iterable параметризуется одним типом. Здесь интереснее — в map приходит union тип, уже лямбда, передаваемая в map информацию о строгом типе теряет.

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


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


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

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

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


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

На самом деле, когда реально важна производительность, там вообще не до коллекций :). Уже и на 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 библиотеки, которые являются обертками над сишными библиотеками. И узким местом является именно сишная библиотека. не подготовка данных, а именно тупой расчет.


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

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

Я немного не понимаю какие тут большие проблемы. Вот код использования из 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$ в конструкторе.

Коллекции свои, написанные с нуля. Если совмещать Java и Ceylon коллекции — да, придется копировать. Синтаксис работы с Java коллекциями достаточно прозрачный и в принципе с Java коллекциями можно довольно комфортно работать. В основном на практике использую Java коллекции, когда мне нужно parallelStream использовать или если использую Java библиотеку. По умолчанию чаще всего стараюсь использовать не List, а Sequence или Iterable, а коллекции только когда реально необходимо. Ибо синтаксис Sequence и Iterable ИМХО гораздо чище. Если коллекции реально нужны, приоритет отдаю цейлоновским, если нельзя (например мне нужны коллекции из пакета Concurrent, а у цейлона на уровне языка поддержки многопоточности нет вообще) — используем Java коллекции. Один разок я даже Scala коллекции решил заюзать, завелось без проблем.
Ceylon не 0. А в настоящее время минимум 1 вакансия, а то и вообще 3. В вакансии только нет ни слова про Ceylon, там Java стоит, кандидатов шокируют позднее :). Актуально для Питера, деньги не суперские, но и не совсем доширак, если кому интересно — можно в личку стучаться.
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
Это тоже делается. Например через рефлексию. Грубо говоря, достается шаблон типа, он параметризуется нужным типом, и далее инстанцируется. Получается да, громоздко и неудобно, даже на цейлоне это не совсем тривиально. Но если есть такая необходимость — это все делается. На практике же лучше такого высшего пилотажа избегать, и если потребуется чтоб ceylon код вызывать из Java — лучше предоставить там Java API без всяких овеществленных дженериков. Если есть такая возможность, естественно.
Либо его недостаточно пиарили. Либо я что то пропустил:
1) Как у groovy с иммутабельностью по умолчанию?
2) Как там дела с for comprehensions?
3) как там дела с деструктуризацией кортежей, причем чтоб деструктуризация была прямо в лямбдах?
4) Как там с женериками? Можно ли в groovy у List узнать в рантайме тип T?

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

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


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

И 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. Весьма поднимает это все производительность разработки.

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

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

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


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

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

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

Information

Rating
Does not participate
Location
Санкт-Петербург, Санкт-Петербург и область, Россия
Registered
Activity