(14-04-2016 16:04)Bʰudʰ писал(а): Try.ceylon-lang.org при нажатии кнопки Run выдаёт «Unhandled Error: Security violation» в DragonFly.
Чё-т мне стрёмно в хроме его запускать.
Хм, ну, тут я точно не скажу, что там может быть такого в JS, что будет так себя вести. Это может быть из-за запуска сгенерированного, а не имевшегося изначально, кода? Всё-таки там компиляция в JS, не интерпретация.
(14-04-2016 16:54)Agrest писал(а): Насколько Ceylon удобен без IDE?
Честно сказать, я не пробовал без, но верю, что не менее, чем, скажем, Python без IDE. Минимальный состав проекта небольшой, загрузить недостающие модули или сделать к коду документацию просто. Ошибки компиляции уж точно выведутся в понятном виде (с отрывком кода). Не знаю, имел ли ты в виду что-нибудь из этого.
(14-04-2016 16:54)Agrest писал(а): Ещё, зная интерес топикстартера к Ашкелю, хотелось бы узнать, в чём Ceylon лучше или хуже Haskell’а.
Да, тут благоприятная почва для сравнений.
• Интерфейсы здесь ближе к классам типов хаскеля — можно включать в них код. C# и Java летят мимо, к сожалению.
• В хаскеле нет разницы между функцией нуля аргументов и значением. В цейлоне есть, но зато там не различается то, что в традиционном языке с ООП было бы полями и свойствами.
• Функциональная сторона довольно богатая. В 1.2 появились if и switch в виде выражений и let. Можно разобрать кортеж/последовательность или ключ-значение на части подобно паттерн-матчингу. В стандартных модулях полно функций второго порядка (или как они там называются).
• А вот синтаксиса, который мог бы сравниться с блоком do в хаскеле, нет. Несмотря на то, что в C#, хотя там и нет абстракции для монад, можно использовать LINQ с вполне осмысленным синтаксисом. В отсутствии методов расширения это, правда, было бы обычно трудновато, а в цейлоне их нет.
• Импорт имён не менее хорош, чем в хаскеле. Можно выбрать, что импортировать, можно сделать это с другими именами, можно импортировать отдельные атрибуты чего-то статического (статического класса джавы или объекта цейлона), можно переименовывать даже отдельные методы какого-нибудь класса. Что лучше хаскеля, в отдельном файле
module.ceylon
указываются ещё и версии модулей, из которых ты что-то берёшь. С хаскелем без использования дополнительных вещей мне приходилось быть уверенным, что стоит правильная версия чего-нибудь.
• В хаскеле можно образовать «пересечение» классов типов, написав их вместе в ограничениях на интересующий тип. С объединением так не просто не получится и придётся писать отдельный класс с инстансами для всех типов объединения.
• Одинаково хорошо присутствует конструкция алгебраического типа данных. В цейлоне многословнее, правда — но там-то для типа определяется не только то, из чего состоят его значения. Можно написать, чтобы потомками указанного класса (или интерфейса!) были только перечисленные классы/интерфейсы/объекты (/конструкторы, когда у классов появилось больше одного конструктора с разными именами). Это ещё и повлияет на поведение switch по значениям такого класса/интерфейса (компилятор сможет быть уверен, что альтернатив не больше и не меньше, чем надо). Так можно определять enum’ы.
• Отношение к null разные, но примерно одинаковой строгости, что исключает NullArgumentException и иже с ним:
— в хаскеле у нас для опциональных значений есть типы
Maybe a
, о которых я писал здесь, должно быть. Тут просто технически не перепутаешь
Just значение_типа_a
и
Nothing
, потому что поматчить сразу оба конструктора не получится;
— в цейлоне используется объединение с типом
Null
, у которого есть одно значение
null
, и у этого типа нет вообще никаких методов или других атрибутов, а так же от него нельзя наследовать, так что пересечение
Null
с любым «атомарным» типом будет пустым. Это позволяет написать
A|Null a = ...
// здесь нельзя ничего сделать с a, потому что объединение содержит только те методы/значения, которые определены для всех объединяемых типов
if (is A a) {
// здесь a имеет тип уже просто A
} else /* if (is Null a) */ {
// здесь a имеет тип Null и потому всегда значение null
}
обычно это пишется более человечески:
A? a = ...
if (exists a) {
// ...
} else {
// ...
}
причём есть ещё синоним
nonempty
для проверки на непустоту последовательности (неизменяемый аналог массива) (это выразимо в типах).
• То, что условия специального вида в if (в том числе выражении и фильтре в comprehension), while и assert меняют типы внутри блоков (или ниже по тексту для assert), называется flow-sensitive typing. В хаскеле его нет, и мало где оно есть. Между тем, это очень удобно и даже отдалённо напоминает паттерн-матчинг. Кто писал на C#/Java/etc. код типа
if (a is T1) {
var a1 = (T1)a;
// поехали с a1
} else if (a is T2) {
var a2 = (T2)a;
// используем a2
} else ...
тот поймёт!
• Матчинга сейчас в цейлоне во всей полноте нет, но для кортежей/последовательностей и пар ключ-значение есть destructuring — растаскивание на переменные. Это можно делать практически в любой конструкции, где можно поставить присваивание, как, собственно, и должно быть.
• Comprehensions есть и там, и там. Синонимы типов — тоже. А вот newtype без расплаты при выполнении кода в цейлоне нет (хотя в Scala, к примеру, есть).
Бонусы без параллелей с хаскелем:
• Метамодель (то, что обычно называется reflection), хорошо относящаяся к типам.
• Нет кучи уровней доступа private/protected/public/internal/etc., есть только shared (и не указание этого слова) и аккуратное управление видимостью пространств имён (которые тут зовутся пакетами).
• Поля и свойства неразличимы (и зовутся values) пользователем твоего кода.
• Различение final/sealed. Ещё различие между абстрактностью класса (abstract) и абстрактностью его атрибута (formal), потому что последним может быть вложенный класс, который можно будет по-разному определить в потомках(!). И ещё есть абстрактные конструкторы — они инициализируют какой-то общий кусок объекта и могут вызываться из других, чтобы уменьшить дублирование кода.
• Спецификация языка набрана не в ворде(!!!)