Статьи

Ява, Скала, Цейлон: Эволюция в чашке Петри JVM

Цейлон — чудесный новый язык JVM от Гэвина Кинга, создателя Hibernate. Он входит в многолюдное поле — с тех пор, как новаторский язык Scala Мартина Одерского продемонстрировал возможность для языков, не являющихся Java, нацеливаться на байт-код JVM, языковая сцена на основе JVM приобрела профиль роста неочищенного яичного микроволокна за пять минут на HIGH.

Теперь у нас есть Kotlin, Clojure, Groovy, Jython, JRuby, Mirah, Gosu, Fantom, Frege, Haxe и длинный конечный континуум более неясных языков на основе JVM на разных стадиях завершенности после этого. Даже сама Java теперь содержит в себе полный движок JavaScript, который является реальным криком для тех, кто может вспомнить раннюю борьбу JavaScript за уважение как реальный язык, когда такие термины, как «Turing Complete», не были Googleable (они были только AltaVistable). и StackOverflow еще не кешировал ответ почти на все, что вы можете осмелиться задавать (а затем закрыл вопрос как неконструктивный).

Но из этого многолюдного поля JVM, Ceylon выделяется как исключительно хорошо сделанный, элегантный и, вероятно, преуспевающий в нише «перспективного Java-разработчика», в которой сейчас доминирует Scala, и, более того, акцент Ceylon на инструментах, продуктивности команды и удобочитаемости означает, что он вполне может занять и часть основного рынка Java.

Конечно, многие языки JVM даже не конкурируют в одном пространстве; они были разработаны с другой аудиторией и целью. Например, многие не заботятся о безопасности типов, некоторые отказываются от производительности в пользу подхода интерпретатора, а некоторые отдают предпочтение обратной совместимости с синтаксисом Java, действуя скорее как расширение языка (и принимая весь свой унаследованный багаж за ездить). Интересно, что Fantom и Groovy пытаются найти что-то среднее между безопасностью типов и типизацией утки с помощью дополнительной типизации.

Как только эти Java-неконкуренты будут удалены, а также все те, которые все еще находятся в состоянии выпуска до 1.0, у нас останутся Java 8, Scala, Kotlin (технически пока не совсем на 1.0, но очень близко), Gosu, и Цейлон работает в аналогичном пространстве. Давайте посмотрим, что делает Цейлон особенным.

Все современные конструкции

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

Цейлон серьезно относится к упаковке

Система модулей Ceylon автоматически генерирует и встраивает файлы pom.xml для управления зависимостями в стиле Maven и извлечения, а также манифеста OSGI для детального контроля того, где они видны — если вам когда-либо понадобились две разные версии одна банка для разных частей вашего приложения, вы оцените это. Затем репозиторий Ceylon’s Herd предоставляет все необходимые зависимости не только во время компиляции, но и во время выполнения (напоминает систему Grape для Groovy).

Типобезопасное метапрограммирование

Вау. Я не знаю , какой — либо другой язык , который имеет это.

Вот что меня всегда раздражало в Java: если бы я хотел сослаться на имя метода или поля, то для этого не было бы способа, проверенного компилятором. Например, если я пишу HQL Hibernate-запрос для поиска фильмов, созданных в 1975 году, я мог бы написать «выбрать из фильмов, где год = 1975», но все обещания безопасности Java во время компиляции просто вышли из окна, потому что когда я переименуйте мое поле «year» в «releaseYear», ничто в компиляторе не напомнит мне также изменить этот запрос.

Даже API Criteria, несмотря на все его проблемы, меня здесь не спасает, потому что в конечном итоге он все же сводится к непроверенной строке в определении критерия. Как насчет отражения? Нет, я, конечно, могу использовать отражение для получения экземпляра Method (или в Scala я даже могу получить экземпляр MethodSymbol из AST), но вот кикер: чтобы получить ссылку на этот объект, мне все равно нужно передать строку указание, на какой метод я бы хотел сослаться, что возвращает меня к исходной точке!

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

До недавнего времени Scala предлагал очень мало собственных рефлексивных возможностей, помимо того, что предоставляет Java, но в последнее время они начали заполнять свои API отражения в выпусках 2.10 и 2.11. Они также представили экспериментальный API предварительной обработки макросов, но, как я вижу, описанный мной вариант использования по-прежнему невозможен (хотя вам может понравиться читать о многих случаях использования символа _, когда вы ищете способ сделать это). Это). Kotlin и Gosu также не могут этого сделать (однако Kotlin объявил о лучшей поддержке метапрограммирования в качестве будущей цели).

Без лишних слов, вот пример, демонстрирующий, как это сделать в текущей версии 1.1 Ceylon:

class Movie (shared Integer year) {}

shared void run() {
    value d = `value Movie.year`;
    print( d.name); //prints "year"
}

Если в методе run вы введете «year» (эквивалент Ceylon для java Main), компилятор поймает это. Красивая! Это на самом деле особенность, которая продала меня, кусок сопротивления, чаша M & M без коричневого цвета, которая сигнализировала мне, что я могу расслабиться, эти парни «получают это» (где «это» определяется как вещи, которые меня действительно волнуют !). Мета-программирование — сложная вещь, и на Цейлоне она выглядит удивительно чистой, но при этом остается безопасной для типов. Единственными специальными символами здесь являются обратные метки, которые означают «получить метамодель для вещи, заключенной в эти метки».

Между прочим, на Цейлоне гораздо меньше вещей типа операторов космических кораблей, чем на Scala (что может быть прямым Perlish). Для меня это плюс для удобочитаемости и простоты понимания в команде. Цейлон также ловко уклоняется от маркера DSL, что является еще одним плюсом для читабельности команды, но при этом учитывает некоторые стимулы, стоящие за DSL, только более разумным и более управляемым способом.

Цейлон также может работать на JavaScript

Это на самом деле не уникально для Цейлона — Kotlin и Fantom также предлагают это — но это не делает его менее странно крутым для меня. У Ceylon есть две реализации компилятора: одна для JVM, а другая для JavaScript, но я чувствую, что JVM все же получает немного больше внимания, поэтому время покажет, насколько хорошо реализация JavaScript идет в ногу. Я полагаю, что это может быть отличной возможностью для интеграции работы внешних и внутренних команд, и в любом случае приятно иметь возможность запускать примеры из учебника прямо в вашем браузере. Это также дает мне надежду, что однажды могут появиться другие реализации, возможно, даже не связанные с JVM? (Чтобы быть уверенным, я спросил команду Цейлона об этой возможности; в настоящее время нет планов для этого в дорожной карте).

Некоторые отличные идеи в системе типов

По большей части, не было много инноваций в безопасности типов среди основных языков после предполагаемых типов Scala. Интересно, что Gosu позволяет своей расширяемой системе типов включать элементы, которые традиционно не проверяются по типам, например, ваш XML-файл конфигурации, но когда дело доходит до того, как обрабатываются типы в самой программе, языки пост-Scala, похоже, понравились и приняли Предполагаемые объявления типов в Scala, но затем посмотрели на поддержку генериков в Scala и пришли к выводу, что это предел того, что является практичным, и, наконец, остановились на регрессии из этой крайности, чтобы восстановить простоту за счет некоторой безопасности и правильности.

Но Цейлон посмотрел на проблему свежим взглядом и нашел блестяще простые улучшения, которые привели к еще более сильной, безопасной и простой системе типов, чем у Scala! Невероятно!

Ключевым нововведением является введение в Цейлоне объединенных , пересеченных и перечислимых типов, которые в основном позволяют объединять существующие типы в агрегированный тип (и сами эти типы могут быть снова аналогичным образом агрегированы — подумайте о выразительной силе дерева). Этот мастер удар удивительно полезен!

Например, тип объединения — это то, как Цейлон отслеживает то, что эффективно обнуляется, устанавливая правило, согласно которому класс Null можно назначать только типу, объединенному с Null. Такие типы могут быть легко объявлены на лету по мере необходимости — вот, как объявить тип, который может быть обнуляемым:

//convenient shorthand way to declare a Nullable type by following it with a question mark
YourTypeHere?

//the above is just syntax sugar for this
YourTypeHere|Null

Затем компилятор принудительно проверяет любой экземпляр этого типа на Null перед использованием. Результат: исключения NullPointerException возможны только в Цейлоне, когда он взаимодействует с Java, и не возможны в чистой программе Цейлона . Как насчет этого, больше нет NPE! (Между прочим, Kotlin также предлагает аналогичный синтаксис для предотвращения NPE, но мне нравится, как обобщается подход Цейлона, когда NPE — это только одна из целого ряда проблем, рассматриваемых типом объединения). 

Другим примером умного нововведения Цейлона в действии является его кортеж (кортеж — это список, содержащий смешанные типы — нет ничего сложного для программ типа утка, таких как Ruby / JRuby или Python / Jython или Lisp / Clojure, но исторически проблематично для строго типизированных языков как Java). Цейлон реализует кортежи как вложенные объединения, которые позволяют Цейлону создавать кортежи произвольной длины.

Напротив, кортежи Scala имеют произвольную длину по-разному — они произвольно ограничены 22! Если вы хотите использовать кортеж из 23 элементов в Scala, вам не повезло! Тем временем Java и Gosu вообще не предоставляют кортежи, и Kotlin избавился от них как слишком надоедливых. Конечно, благодаря простоте определения импровизированных классов некоторая потребность в кортежах устраняется во всех этих языках, но кортежи по-прежнему оказываются полезными при поддержке функциональных идей, таких как карри, и того факта, что только Цейлон мог бы предоставить их так легко без какого-либо специального языка. конструкции является свидетельством силы системы типов.

Дженерики и Святой Грааль JVM: типизация

Дженерики — это то, где системы типов обычно распадаются, быстро. Они также хорошо разбираются в обзорах высокого уровня, таких как этот, поэтому достаточно сказать, что Java пошла на серьезные компромиссы в своем подходе к генерикам, с тем предлогом, что это лучшее, что можно было сделать без изменения JVM (альтернативной JVM). — с тех пор авторы языка доказывают, что они не правы). Цейлон снова сделал умные идеи, чтобы еще больше упростить ситуацию, и в то же время он каким-то образом также предоставил переработанные дженерики (способность восстанавливать обобщенно скомпилированную информацию о типах во время выполнения, казалось бы, невозможный подвиг, учитывая архитектуру стирания типов в Java, благодаря которой универсальные типы отбрасываются во время компиляции). Gosu — единственный другой язык, который обладает этой способностью, которая упрощает широкий спектр задач программирования. Я неЯ не знаю, через какое вуду было внедрено, но я впечатлен, увидев это там.

Все предмет

Людям нравится это в Ruby. Я люблю это и о Цейлоне. Он последовательный и эгалитарный … никакой особой магии нет только для Цейлона. Большинство символов, таких как [] и +, являются просто краткими способами вызова базовых вызовов методов со всей гибкостью и преимуществами ориентации объекта. Так, например, выражение 2 + 3 на самом деле является просто сокращением для 2.plus (3):

print( 2.plus(3) ); //prints 5

Ceylon’s online Javadoc-equivalent includes source code

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

Геттеры и сеттеры бесшовные

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

Scala, Kotlin, Gosu и Ceylon работают лучше с геттерами / сеттерами, чем с Java. Но Ceylon добавляет приятный штрих: он не только позволяет беспрепятственно добавлять геттеры / сеттеры, когда они вам нужны, к полям классов, он также допускает это для любого значения, независимо от инкапсуляции класса. В Цейлоне прямая ссылка неотличима от кода вызова от перехватывающего getter / setter:

// a regular, directly referenced value
Integer i = 5;
print(i.string); //prints 5

// this value uses a getter/setter, with a backing variable to hold its state.
variable Integer jstate = 5;
Integer j {
    return jstate * 2;
}
assign j {
    jstate = j-1;
}
j = 5;
print(j.string); //prints 8

Заметьте, как ничего не изменилось в вызывающем коде, используя простое значение i по сравнению со значением j, полученным с помощью метода get / setter? Так и должно быть. Кстати, вы, возможно, заметили, что значения с получателями / установщиками больше не могут хранить данные, они должны прокси-сервер обратно к другому объекту для хранения своих данных. Поначалу это выглядит как безвредное, но ненужное ограничение, но на самом деле это имеет смысл с синтаксической точки зрения; в противном случае, как вы когда-нибудь сможете получить доступ к неискаженным базовым данным, учитывая, насколько неразличимы методы доступа к необработанным и полученным данным?

Одна вещь, которую я всегда желал в Java, — это обобщение этой возможности бесшовного переноса, так что все вызовы методов в классе могут быть опционально упакованы другой парой методов (один непосредственно перед, другой сразу после вызова метода). Это устранит большую часть необходимости в AOP и многих других обходных решениях Java и, как правило, упростит реализацию шаблонов декоратора. Ruby / JRuby имеют эту возможность; возможно, однажды, один из языков JVM с проверкой типов тоже может получить его вариант. До тех пор, я рад видеть улучшение геттеров / сеттеров Цейлона.

Наконец, моя крошечная жалоба

Моя единственная жалоба, и ее тривиальность показывает, как далеко я должен копать, чтобы найти что-то, на что можно жаловаться, — то, что Scala и Kotlin оба использовали короткие ключевые слова «var» и «val», чтобы отличить изменчивые от неизменяемых переменных, Цейлон выбрал «переменная» и «значение». Я могу жить с этим 🙂

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

Вывод

Когда Джеймс Гослинг создал Java, это был огромный шаг вперед по сравнению с тем, что существовало в то время. Влияние Java на мир вряд ли можно переоценить, но, возможно, еще большим был черный подарок, который она принесла, JVM. В то время как Java растёт долго в зубе, возникло множество языков, чтобы использовать его двойник, JVM. Из этих языков следующего поколения все имеют свои достоинства, но Цейлон кажется особенно многообещающим претендентом на то, чтобы когда-нибудь заменить Java. Может ли Java догнать или, возможно, взять страницу из старой книги Microsoft и «принять и расширить» эти функции, покажет только время. В то же время, Цейлон представил захватывающую реализацию того, что уже возможно на JVM прямо сейчас.