Почему Fantom?

    Fantom — это объектно-ориентированный, статически-типизированный язык общего назначения, разработанный братьями Фрэнками (Brian Frank, Andy Frank). Одна из ключевых особенностей Fantom — это мощная стандартная библиотека, абстрагированная от конкретной среды, в которой она будет исполняться. В данный момент код, написанный на Fantom, можно запустить в Java Runtime Environment (JRE), .NET Common Language Runtime (CLR) или же скомпилировать в код на JavaScript.

    class HelloWorld
    {
      static Void main() { echo("Hello, World!") }
    }
    

    Переносимость


    Основной причиной создания Fantom было написание программного обеспечения, которое может запускаться на двух платформах Java VM и .NET CLR. Реальность такова, что большинство компаний разрабатывают свое программное обеспечение для одной из этих платформ. Даже такие динамические языки, как Python и Ruby работают на одной из этих виртуальных машин. Fantom был создан решить проблему переносимости с одной виртуальной машины на другую. Исходный код Fantom компилируется в fcode — байткод, который легко может быть транлирован в Java байткод или IL. Транслирование происходит во время выполнения, что позволяет развертывать Fantom модуль, как отдельный файл, и запускать на любой VM.

    Портативность означает значительно больше, чем просто Java или .NET. Как было сказано выше, Fantom может компилироваться в JavaScript для работы в браузерах. При этом Fantom не собирается останавливаться на достигнутом, следующие цели — Objective-C для iPhone, LLVM, Parrot.

    Элегантное API


    Хотя о вкусах и не спорят(«Beauty is in the eye of the beholder»), создатели Fantom по-настоящему одержимы красивым и удобным API. Один из основных принципов Fantom. Java и .NET имеют одну общую тенденцию максимального деления функционала на маленькие независимые и абстрагированные единицы (классы). Fantom имеет противоположную философию — они верят, что можно обойтись малым, но мощным количеством единиц.



    Хорошим примером является пакет java.io, который содержит больше 60 классов и интерфейсов, в Fantom все необходимое лежит в четырех классах: File, Buf, InStream и OutStream. И вот так выглядит его использование:

    Void textIO()
      {
        f := File(`text-io.txt`)
        // write text file (overwrites existing)
        f.out.printLine("hello").close
        // append to existing text file
        f.out(true).printLine("world").close
        // read text file as big string
        echo(f.readAllStr)
        // read text file into list of lines
        echo(f.readAllLines)
        // read text file, line by line
        f.eachLine |line| { echo(line) }
      }
    

    Типизация


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

    Со стороны статической типизации, Fantom требует описание полей и сигнатур методов с указанием типов. Это хорошая практика, зафиксировать формат общения между компонентами. К примеру, если я хочу написать метод, который работает со строкой и числом, то это должно быть зафиксировано прямо в коде. В отличие от статической типизации сигнатур методов и полей, в коде она часто только мешает, заставляя писать ненужный код. Вывод типов в Fantom позволяет избежать этой проблемы. Например, громоздкое создание словаря в java:

    Map<Integer, String> map = new HashMap<Integer, String>();
    map.put(1, "one");
    map.put(2, "two");
    

    Эквивалентно в Fantom одной строчке:
    map := [1: "one", 2: "two"]

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

    С другой стороны, вы можете использовать оператор "->", для указания динамического вызова. На самом деле, "->" будет перенаправлен на вызов Obj.trap. По умолчанию trap работает как ".", но только во время выполнения. Вы можете изменить это поведение, определив свой динамический дизайн.

    if (a is Str) { return a->toInt }
    obj->foo         // obj.trap("foo", [,])
    obj->foo(2, 3)   // obj.trap("foo", [2, 3])
    obj->foo = 7     // obj.trap("foo", [7])
    

    Дженерики


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

    В настоящий момент у Fantom ограниченная поддержка дженериков — пользователь не может использовать свои собственные. Однако, три встроенных класса могут List, Map и Func. К примеру, список целых чисел в Fantom объявляется как Int[]. Создатели Fantom считают, что попали в середину: дженерики есть, но без усложнения системы.

    Примеси


    Вопрос сопоставления модели из предметной области в код — один из самых часто решаемых вопросов в разработке программного обеспечения. Обычно в объектно-ориентированном программирование данная фраза означает моделирование классов и интерфейсов. Java и C# используют одинаковый подход: классы поддерживают одиночное наследование, интерфейсы множественное наследование, но не поддерживают наследование реализаций.

    Каждый, кто работал с Java или C#, знает, что выбор между созданием класса или интерфейса очень важен. Потому что, если вы выберете класс, то вы используете свой единственный шанс на наследование реализации. Если у вас большая и сложная модель, то интерфейсы становятся дополнительной нагрузкой. К примеру, если есть два объекта, имеющих разных наследников, и одинаково реализующие один и тот же интерфейс, функционал придется продублировать. Кроме дублирования есть проблема изменение версии интерфейса, которая затрагивает все реализации.

    Есть множество хороших причин почему Java и C# используют модель классов/интерфейсов. Множественное наследование открывает многие двери, но происходит это за счет увеличения сложности и довольно неприятных нюансов. Fantom снова занимает середину, называемую примеси (mixins). Примеси — это интерфейсы, которую могут хранить в себе реализацию. Чтобы избежать ошибок множественного наследования, у примеси ограничены некоторые функции, такие как поля, хранящие состояние. Пример примеси:

    mixin Audio
    {
      abstract Int volume
      Void incrementVolume() { volume += 1 }
      Void decrementVolume() { volume -= 1 }
    }
    
    class Television : Audio
    {
      override Int volume := 0
    }
    

    Если интересно, java эквивалент можно посмотреть здесь.

    Модульность


    Модульность — важный аспект программного обеспечения, который необходим современному языку программирования.
    К сожалению, последнюю декаду в java мы испытываем настоящий ад с classpath. Кроме проблем с classpath, java приняла неправильное решение и перешла к монолиту J2SE размером 44Mb, что значительно замедлило наши с вами приложения.
    В .NET подошли к этому вопросу крайне серьезно, поэтому благодаря механизму версий, GAC и другим средствам часть проблем из Java была решена. Но они утеряли простоту zip модуля и начали паковать модули в DLL, которые содержат еще много разных запчастей, что не позволяет легко работать с модулем.

    В Fantom все строится на модулях, называемых подами (pods). Как и в java, под — это просто zip файл, который можно легко посмотреть. Мета данные пода хранится в специальном файле /meta.props, представляющее собой записи вида ключ-значение, такие как pod.name, pod.version, pod.depends и так далее. Зависимости пода хранятся в его мета данных и описаны в явном и понятном виде.

    Для организации кода в пространстве имен в java используются пакеты, а jar файл рассматривается как модуль. Несоответствие между этими понятиями вызывает большую проблему. У вас есть имя java класса, но оно вам не подскажет в каком jar файле живет этот класс и откуда его загружать.

    В Fantom было принято простое решение для управления имен: три уровня иерархии в имени «pod::type.slot», т.е. на первом уровне всегда имя пода, затем имя типа (аналог Class в java) и затем имя слота (метод или поле). Такое согласованное поведение в пространстве имен позволяет легко управлять процессом сборки больших систем.

    Функциональное программирование


    Java и C# движутся в направлении полноценной поддержки замыканий, но после себя они оставляют большой след истории, в качестве старого API. Fantom создавался с поддержкой замыканий на начальной стадии. Замыкания — ключевая особенность языка, которая используется везде и всегда.

    // print a list of strings
    list := ["red", "yellow", "orange"]
    list.each |Str color| { echo(color) }
    
    // print 0 to 9
    10.times |i| { echo(i) }
    
    // create a function that adds two integers
    add := |Int a, Int b->Int| { return a + b }
    nine := add(4, 5)
    
    // map Int to Str
    map := [0:"zero", 1:"one", 2:"two"]
    
    // empty Int:Str map
    Int:Str[:]
    
    // map
    [1, 2, 3].map { "f" + it * 2 } // ["f2", "f4", "f6"]
    
    //reduce
    ["2":2, "3":3, "4":4].reduce(0) |Int sum, Int v->Int| { sum + v } // 9
    

    Декларативное описание


    Наилучшим описанием будет пара примеров:

    Window
    {
      title   = "Example"
      size    = Size(300, 200)
      content = EdgePane
      {
        center = Label  { text = "Hello world"; halign = Halign.center }
        bottom = Button { text = "Close"; onAction.add { it.window.close } }
      }
    }.open 
    
    homer := Person
    {
      name = "Homer Simpson"
      age  = 39
      children =
      [
        Person { name = "Bart";   age = 7 },
        Person { name = "Lisa";   age = 5 },
        Person { name = "Maggie"; age = 1 }
      ]
    }
    

    Параллелизм


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

    Fantom поддерживает параллелизм, используя следующие техники:
    1. Неизменяемые объекты (потоковая безопасность)

      const class Point
      {
        new make(Int x, Int y) { this.x = x; this.y = y }
        const Int x
        const Int y
      }
      
      p := Point(0, 0)  // ok
      p.x = 10              // throws ConstErr
      
      vowels := ['a','e','i','o','u'].toImmutable
      

    2. Статические поля могут хранить только неизменяемые объекты, поэтому разные потоки не могут получить доступ к общим изменяемым данным.
    3. Модель сообщений (actors) для общения между потоками (Erlang-style)

          echo("\n--- echoActor ---")
          // this actor just echos messages sent to it
          a := Actor(ActorPool()) |msg| { echo(msg); return msg }
      
          // send some messages and have them printed to console
          f1 := a.send("message 1")
          f2 := a.send("message 2")
          f3 := a.send("message 3")
      
          // now block for the result of each message
          echo("Result 1 = " + f1.get) // message 1
          echo("Result 2 = " + f2.get) // message 2
          echo("Result 3 = " + f3.get) // message 3
      


    Синтаксический сахар


    1. Значения по умолчанию для параметров

      class Person
      {
        Int yearsToRetirement(Int retire := 65) { return retire - age }
        Int age
      }
      

    2. Вывод типов — типы локальных переменных могут быть выводимыми
    3. Неявный доступ к полям

      class Thing
      {
        Int id := 0
        {
          get { echo("get id"); return &id }
          set { echo("set id"); &id = it }
        }
      }
      

    4. Нулевые типы — разделение типов на те, которые не могут принимать null, как значение, и которые могут.

      Str   // never stores null
      Str?  // might store null
      
      x := str.size   =>  x is typed as Int
      x := str?.size  =>  x is typed as Int?
      

    5. Убраны проверяемые исключения, в C# Anders Hejlsberg также не включил их (и правильно сделал)
    6. Числовая точность — существует только 64 разрядная поддержка Int и Float


    Ресурсы


    1. Fantom eclipse-based IDE F4


    2. Web applications framework Tales
      //Hello world written in tales
      using tales
      
      class HelloWorld : Page{
        @Route{uri="/hello-world"}
        Void main(){
          response.writeStr("Hello World")
        }
      }
      

    3. Logic-free template engine Mustache
      using mustache
      Mustache template := Mustache("Hello, {{ name }}!".in)
      template.render(["name":"world"])
      

    4. Fantom Pod repository


    5. fantom.org


    Заключение


    Распространённой ошибкой является мнение, что Fantom — это очередная улучшенная версия Java. Но стоит только взглянуть на него, как на язык со своей философией и концепциями, как начинаешь понимать всю его прелесть. Помимо стабильности, к Fantom можно отнести ряд таких особенностей, как дружелюбное сообщество, полностью открытый исходный код, приятную IDE и ещё множество приятных мелочей.
    Поделиться публикацией
    Комментарии 48
      +2
      Сугубо личное мнение, но по-моему, такое можно сказать о любом новом языке/инструменте, который хочет своей аудитории и популярности: «можно отнести ряд таких особенностей, как дружелюбное сообщество, полностью открытый исходный код, приятную IDE и ещё множество приятных мелочей.»…
        0
        Согласен с вами. Но вот своей философией и концептуальной целостностью могут похвастаться очень немногие языки. Особенно это заметно, когда в него добавляется новая возможность. Если у языка нет целостности, то он начинает собирать в себе все возможные фичи, превращаясь в итоге в месиво, в котором крайне сложно разобраться.

        В Fantom же новые возможности добавляются очень осторожно и от сомнительных расширений предпочитают отказываться. Схожего мнения придерживаются и создатели Clojure, например.
        +21
        Когда я вижу новость о новом JVM-based языке программирования (via):

        image
          +1
          Предпочитаете писать на Java?
            +5
            Java, Groovy, Scala (после Scala пока никакой JVM-based язык нет желания и необходимости изучать).
              +1
              Scala не идеальна. Я во многом солидарен с создателем JodaTime Стивеном Колборном, который высказывается своё мнение о Scala в большой статье Scala feels like EJB 2, and other thoughts.
                +1
                А как насчет Clojure? Как вы считаете, выигрывает у Fantom'а или нет?
                  0
                  Неожиданно своевременный вопрос :-) Я совсем недавно ушёл из «евангелистов» Фантома и переключился на Кложу. У Фантома при всех его плюсах есть один большой недостаток — его никто не использует. А по Clojure буквально на днях прошёл хакатон, в котором я с огромным удовольствием принял участие. Можно почитать подробнее, если интересно.
                  0
                  За то в ней есть pattern matching и не различаются statment и expression.
                    0
                    Кстати, Scala поощряет создание иммутабельных структур. Нужна ли возможность проверить иммутабельность произвольного объекта я не уверен.
                –2
                Fantom не такой уж и новый, на самом деле. Если заглянуть в changelog, можно узнать, что первый релиз был аж в сентябре 2005.

                Картинка конечно смешная, но подпись к ней подкачала. Да и не новость это, а скорее brief overview, так что ваши мотивы запостить «смешную картинку» на читая топика мне не понятны.
                0
                Как язык интересен. Но вот область применения у него какая? Какой язык из какой ниши он «должен» вытеснить? Есть ли у него необходимый «отвес»?
                  0
                  Я думаю у языка большой потенциал. Во-первых, это конечно же серверные приложения. Мне доводилось сравнивать Tales с Play и моё первое впечатление — почему первое настолько быстрее второго? Плюс лично мне концепции Tales кажутся более правильными, тот же «html stays html» в шаблонах. С другой стороны, у этих проектов совершенно разный размер комьюнити, а потому и Play намного более стабилен.

                  Во-вторых, мне кажется, что Fantom мог бы стать хорошей платформой для разработки графических приложений. Например, кросс-платформеных мобильных приложений. Во-первых, он был создан для того, чтобы работать в разных средах. Во-вторых, декларативный синтаксис и прочие возможности делают его очень удобным для описания интерфейсов. Fantom в чём-то похож на JavaFX Script который не пытается встроить в мой браузер дурацкий java plugin, а транслируется с честный JavaScript.
                    0
                    К слову о серверных приложениях
                    >Running the code in Production mode
                    >To run code in production mode use the «exec» command instead of «run». Open command prompt. Cd to the application directory and type
                    >fan tales exec
                    >That's it. Your code is running production mode now.

                    И как же прикрутить к другому серверу, например к jetty? Или что придется весь функционал веб-сервера еще самому реализовывать?
                    Или например как реализовать сервлет на этом Fantom?
                      0
                      Насчёт запуска Tales в jetty я, к сожалению, не знаю. Хотя даже если этого ещё нет, я не думаю, что это слишком сложная задача, учитывая возможности Fantom. Кроме того, на сколько я помню в Play 2 с этим всё ещё проблемы.

                      Fantom может использовать Java, кроме того у него есть встроенный простой веб-движок, который уже давно запускается в любом контейнере сервлетов.
                  0
                  Сначала были машинные коды. Потом asm. Дальше прикладные языки ( можно считать 1м уровнем абстракции), потом появились вируальные машины (CLR, JVM) и к ним языки 2го уровня асбтракции, сейчас благодаря LLVM — все больше новостей о языках 3го уровня…
                  Интересно на этому процесс остановится? :)
                    +2
                    >Portability
                    >Write code portable to the Java VM, .NET CLR, and JavaScript in the browser.

                    fantom.org/doc/sql/index.html
                    Что то не видно примера для Javascript или хотя бы для .NET
                      0
                      Ну ведь очевидно, что это не более чем «рекламный слоган». Привязки к VM не будет только если мы используем исключительно native-библиотеки. Которые в свою очередь должны иметь полностью совместимые порты под разные VM. Выглядит утопично.
                        0
                        Fantom не предлагает невозможного, он предлагает прозрачный способ написания переносимого кода. Например, стандартная библиотека работает во всех трёх VM. Модуль actors работает только для Java и .NET, поскольку в JavaScript он и не нужен (по крайней мере пока). А допустим fwt (Fantom Widget Toolkit) предоставляет один и тот же интерфейс для доступа к SWT на java и DOM для веба.

                        Я несколько лет назад занимался разработкой RichText, который отрисовывался на canvas в HTML5 и SWT используя один и тот же код на Fantom. При этом там, где нам нужно было, мы совершенно прозрачно использовали jQuery в JS или скажем JFace в Java.
                        +1
                        В настоящий момент у Fantom ограниченная поддержка дженериков — пользователь не может использовать свои собственные. Однако, три встроенных класса могут List, Map и Func. К примеру, список целых чисел в Fantom объявляется как Int[]. Создатели Fantom считают, что попали в середину: дженерики есть, но без усложнения системы.

                        Может просто не осилили реализовать, учитывая различия между дженериками Java и CLI (C#)? А там еще и JS заявлен…
                          0
                          Интересно, получается 3 типа (List, Map и Func) по сути имеют статус «встроенных», на подобие массивов в Java. И реализуются они на уровне компилятора/языка, а не на уровне библиотеки?
                            0
                            Не совсем так. Они, как и все остальные нативные типы стандартной библиотеки, реализуются для каждой из платформ. Кроме того, в компиляторе уже есть поддержка дженериков. Но возможная область применения этих дженериков пока ограничивается только этими тремя типами.
                            +4
                            Как только увидел статью про Fantom, первая мысль — уж не в xored ли работает автор? :) Пять минут в гугле — и точно. Интересно, хоть кто-то в России еще работает с этим языком?
                              +1
                              Наша компания серьёзно рассматривает этой язык и с большой вероятностью мы будем его использовать. Но правда я — основной идеолог и ex-xored :-)
                                0
                                ex-xored — как звучит! :)
                              0
                              А мне понравилось. Пока применения особо не вижу, но для себя, для развития изучить захотелось, чем и займусь на досуге.
                                0
                                Я в комментарии выше немного раскрыл эту тему. Может быть вас что-то заинтересует.
                                  0
                                  Да, в чем-то вы правы. Особенно в отношение графических интерфейсов, потенциал большой.
                                0
                                Java перевешивает все плюшки своей популярностью и простотой. А где искать разработчиков для этого языка? Только обучать.
                                  0
                                  Одно из главных достоинств Fantom — это его простота и схожесть с Java/C#. У меня есть опыт обучения новых людей этому языку и могу вам сказать совершенно точно — гораздо проще найти людей, способных освоить Fantom, чем тех, кто может писать многопоточный код на Java.
                                    0
                                    А можно подробнее, какие средства есть для упрощения создания многопоточных программ.
                                    Ну кроме иммутабелных полей/объектов и акторов (которые есть и в Java).
                                      +1
                                      На самом деле в Java нет ни того, ни другого. Иммутабельность в Fantom гарантируется компилятором, и это не аналог final в Java, это настоящая иммутабельность. Например, константный список может содержать только константные элементы. В Java вы не можете такого гарантировать. В Fantom константность можно определить на уровне интерфейса и тогда его смогут реализовывать только константные типы, никаких внутренних состояний. Даже замыкания делятся на константные и не константные в зависимости от того, используют ли они изменяемое окружение.

                                      В Fantom нет примитивов синхронизации вообще. Никаких мониторов, локов, synchronize-блоков и так далее. Новичок не сможет вызвать дедлок случайно поставив «synchronized» в неправильном месте. Все статические переменные обязаны быть иммутабельными. Потоков в явном виде тоже нет, они могут создаваться только для акторов. И вот уже на базе всего этого строятся акторы. Они мало бы чем отличались от потоков, если бы могли одновременно менять один и тот же объект. В Fantom такого не может быть, поскольку у них есть только внутреннее thread-local состояние и константные объекты, которыми они могут обмениваться со внешней средой.

                                      Справедливости ради стоит заметить, что в Fantom поддержка многопоточности не такая крутая, как, например, в Clojure. Нет персистентных структур данных и нет STM. Но это скорее из-за того, что пока не было большой потребности.
                                  +2
                                  Хорошим примером является пакет java.io, который содержит больше 60 классов и интерфейсов, в Fantom все необходимое лежит в четырех классах: File, Buf, InStream и OutStream.
                                  Зато в InputStream в Java 9 методов, а в InStream 35. Тут уж приходится решать — использовать из кучи непонятных классов один, который полностью понимаешь или из нескольких классов тот, в котором полно ненужных тебе вещей. Кроме того, специализированные варианты потоков и файлов наверняка есть в глубинах этого Fantom, просто наружу не торчат.
                                    0
                                    Главный вопрос: как мне использовать уже имеющиеся JVM-based библиотеки? Я очень ленивый и не хочу писать все с нуля!!!
                                    +3
                                    Очередной байт-код. Чтобы потом его перевести в байт-код.
                                      0
                                      Сразу в глаза бросается первая причина никогда не использовать этот язык — детское название.
                                      Слово, конечно, не детское, но первое впечатление не изменишь
                                        0
                                        А что детского?
                                          0
                                          Ассоциации с комиксами и.т.п
                                            0
                                            У меня с научной фантастикой.
                                        0
                                        А просто интерпретатор байткода есть? А IO в стандартной библиотеке как на опкоды отображается?

                                        Я давно хочу «взрослый» язык, виртуальная машина которого способна работать в произвольном event loop. Lua и JavaScript/V8 не предлагать.
                                          0
                                          Интерпретатор какого байткода? Fantom конечно же умеет интерпретировать свой байткод, он это и делает во время исполнения :-)

                                          Не очень понял ваш второй вопрос, но может быть вам будет достаточно поиграть с Fantom online?
                                            0
                                            По второму вопросу — нечто, что можно встроить в сервер с FSM-архитектурой. Типа nginx/lighttpd.

                                            Я это как вижу:

                                            1) виртуальная машина поддерживает множество контекстов выполнения без необходимости создания тредов или процессов;
                                            2) вычисления: виртуальная машина выполняет сколько сказали тиков и возвращает управление;
                                            3) I/O — виртуальная машина дергает переданный снаружи коллбэк, которому говорит, что надо сделать, и какой коллбэк дернуть, когда будет сделано, и тоже возвращает управление.
                                          0
                                          братьями Фрэнками (Brian Frank, Andy Frank).

                                          Brian Frank я прочитал как Brainfuck…
                                            0
                                            Желаю конечно удачи проекту, но не приведет ли это к тому, что мы опять будем бодаться с кросскомиляцией? И зачем спрашивается вобще нужно было в виртуальные машины тогда съезжать?
                                              0
                                              Спасибо за пост. Я с fan познакомился недавно, но опечалило одно — IDE для него. Что то умней Клипсы мне нужно.

                                              Был плагин fan4idea, но он старый. Его можно конечно поднять к IDEA 13, но ограничения — только Java + JS, меня это огорчает.
                                                0
                                                Спасибо, сам использую F4, насколько мне известно это fantom IDE де-факто.
                                                  0
                                                  Я это знаю, но я сторонник IntelliJ платформы, или exIntelliJ(долго обьяснять). А F4 — eclipse-based.

                                                  Их минус — никто не поддерживает .NET. Это печально. Но поправимо.

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

                                              Самое читаемое