Я только что натолкнулся на язык, о котором никогда раньше не слышал — Фан . После нескольких часов изучения языка я должен сказать, что Фан, похоже, многое понял правильно. Вот краткий список его возможностей:
- Повторно использует синтаксис C # для свойств.
- Дополнительная статическая типизация и вывод типа. Используйте «.» чтобы включить статическую типизацию, «->» для динамической типизации. Несуществующие методы отправляются в универсальный метод «ловушки», который является эквивалентом метода Ruby's_missing . Также возможно создавать типы во время выполнения, которые Fan называет — хотя и немного смущающе, хотя и точно) — «динамические типы».
- Карри с оператором & .
- Затворы. Мне также нравится тот факт, что замыкания и функции Fun можно прозрачно преобразовать в методы (например, «делегаты») с помощью каррирования. Смотрите ниже пример.
- переопределение и виртуальные ключевые слова (в отличие от Java, методы Fan не являются виртуальными по умолчанию).
- Нетипизированные аннотации (называемые гранями). Фасеты — это пары (ключ, значение), и они могут быть проанализированы во время выполнения. Система резервирует для себя несколько имен фасетов, таких как @transient или @serializable .
- Неизменность (классы могут быть созданы const, а объекты могут быть неизменными).
- Смешанные модули (представленные интерфейсами, которые могут иметь реализацию). У встраиваемых дополнений могут быть свойства, хотя они должны быть абстрактными (подход, который я считаю менее строгим, чем у Scala).
- Работает как на JVM, так и на .Net (вау!).
- Использует : = для назначения. Я помню, что мне очень нравился этот символ, когда я программировал на Pascal и Modula 2, но я не использовал его около двадцати лет, так что поначалу это может немного смущать.
- Интересный подход к модульности, использующий REST URI для обозначения пространств имен. Эта область все еще находится в разработке, но вот цитата, которая обобщает подход Фана:
Java и .NET в меньшей степени разделяют понятия пространства имен и развертывания. Например, в Java пакеты используются для организации кода в пространство имен, а файлы JAR используются для организации кода для развертывания. Проблема в том, что между этими понятиями нет никакого соответствия. Это только усугубляет ад путь к классу — у вас есть отсутствующий класс, но имя класса не дает вам подсказки относительно того, в каком JAR-файле может жить класс.
- методы «один раз» (особенность, которую я могу вспомнить, когда-либо видела в Эйфелевой башне).
- Декларации конструктора должны начинаться с ключевого слова «new», но могут принимать любое произвольное имя, хотя обычно используется префикс «make». Создание объекта выполняется путем вызова этого конструктора как статического метода для типа (например, Ruby), который я считаю интуитивно понятным.
- Красивый веб-сайт с расширенной документацией.
Вот несколько примеров кода, иллюстрирующих основные возможности Fan.
Конструктор
class Point { new make(Int x, Int y) { this.x = x; this.y = y; } Int x
Int y } // make a point pt := Point.make(30, 40)
свойства
class Person { Str name Int age { set { checkAge(val); @age = val } } }
В приведенном выше коде @age используется для ссылки на фактическое поле, а не на свойство.
фаска
@version=Version("1.2") @todo=["fix it", "really fix it"] class Account { }
Вы можете передать методы, когда ожидается закрытие. Например, Thread.make ожидает закрытия, которое принимает Thread в параметрах и возвращает Obj:
new make(Str name := null, |Thread -> Obj| run := null)
Вам не нужно создавать объект для вызова этого метода:
static Void readerRun(Thread t) { // ... } reader := Thread.make("reader", &readerRun).start
Вот некоторые из моих любимых мозолей о Фане:
- Синтаксис ввода. Я бы предпочел «f: File-> Bool» вместо «File f-> Bool», чтобы формальные параметры и тип замыкания можно было легко отличить друг от друга.
- Нет дженериков. Все успешные языки в конечном итоге получаются, так что я надеюсь, что Fan тоже будет, но создатели, похоже, враждебно относятся к этой идее:
Наша философия заключается в том, что генерики являются довольно сложным решением довольно незначительной проблемы.
Я уверен, что они передумают в свое время, а тем временем List , Map и Func предлагают ограниченный тип универсальности.
- Кажется, нет никакой поддержки IDE. Я не уверен, сколько лет Fan, но в документации говорится, что он приближается к v1.0, поэтому я надеюсь, что разработчики Fan учатся на ошибках Groovy и сосредоточат свое внимание на поддержке IDE как можно скорее.
- Я предпочитаю, чтобы конструкторы имели фиксированное имя, а не произвольно выбранное разработчиком. В то время как объявления классов позволяют легко определить, какие методы являются конструкторами (просто ищите «new»), это не так просто определить, когда вы находитесь на сайте вызова, так как вызов конструктора нельзя отличить от статического вызова. Исходя из этого, я все еще нахожу, что подход Руби ( Person.new ) представляет собой лучшее из обоих миров, хотя я думаю, что он может быть усовершенствован еще дальше, если полностью исключить двойственность "new" / "init" . Например, вместо:
// Valid Fan class Point { new make(Int x, Int y) { this.x = x; this.y = y; } Int x Int y } p = Point.make(2, 3)
Почему бы и нет:
// Invalid Fan class Point { new(Int x, Int y) { this.x = x; this.y = y; } Int x Int y } p = Point.new(2, 3)
? (то же самое можно сказать о Ruby)
За исключением частичных генериков, Fan, похоже, не добавляет столько инноваций, как его предшественники, что не обязательно плохо. Совершенно очевидно, что авторы Fan хорошо знают несколько языков и перенесли эти концепции, иногда едва модифицированные, в Fan. Говоря о портировании, я впечатлен тем фактом, что Fan работает как на JVM, так и на .Net.
В целом, похоже, что Fan руководствуется мотивациями, которые очень похожи на те, что были запущены в Groovy: выберите лучшие возможности современных популярных языков и попробуйте смешать их в единый набор. Мне особенно нравится Fan, потому что я согласен с большим выбором, который сделали дизайнеры, и это именно то, что я чувствовал к Groovy в начале. Конечно, у Fan есть преимущество в ретроспективе, и он заимствует из нескольких дополнительных языков, чем Groovy (а именно, C #, Scala и немного Erlang), поэтому я нахожу результат довольно многообещающим.