Fantom
                           Cross-VM language




четверг, 24 июня 2010 г.
Общие сведения


                           Объектно-ориентированный

                           Статически типизированный

                           Opensource (Academic Free license 3.0)




четверг, 24 июня 2010 г.
Почему Fantom?
                           Мультиплатформенность

                           Отличный язык

                           Удобство “из коробки” (built-in tools)

                           Интеграция с платформой

                           О@#$%ная IDE от Xored :)




четверг, 24 июня 2010 г.
Мультиплатформенность
                                          .fan


                                 .fcode           .js



                           JVM   .NET     LLVM   Parrot


четверг, 24 июня 2010 г.
Достоинства языка

                           Повышение производительности
                           программиста (по сравнению с Java)

                           Страховка от ошибок

                           Мультипарадигменность

                           Низкий порог вхождения (по сравнению
                           с Scala, Clojure)



четверг, 24 июня 2010 г.
Производительность
                           Литералы

                           First-class функции

                           Замыкания

                           Вывод типов

                           Миксины

                           Множество удобных мелочей


четверг, 24 июня 2010 г.
Литералы
                                             [1, 3, 5, 7]
                              Списки         ["a", ["b", "cd"]]


                               Мапы          ["str": "Str", 1: 3, "list": [null, 5]]


                                             Str#
                           Типы (reflecion)   sys::Str#
                                             Str#capitalize

                                             `ftp://user001:pass@ftp.com/mydir/myfile.txt`
                                URIs         `http://fantom.org`
                                             `/Users/ivaninozemtsev/work/fantom`



                  Временные интервалы [1ns,         5ms, 12sec, 3hr, 1day]



                            Диапазоны        [1..5, 2..8, 0..<5]




четверг, 24 июня 2010 г.
Функции и замыкания
                                   //simple signatures
            Функции как объекты    |->| voidSig := |->| {}
                                   |->Int| returnsInt := |->Int| { 42 }




                 Методы содержат   |Int a, Int b ->Int| plus := Int#plus.func

                     функции
                                   |->| mainFunc := #main.func




      Функции могут связывать      opFunc := |Method m, Int a, Int b| { m.callOn(a, [b]) }
                                   mul := opFunc.bind([Int#mult]) //|Int, Int->Int|

            аргументы              plus2 := opFunc.bind([Int#plus, 2]) //|Int -> Int|




       Замыкания - выражения,      Str prefix := ""

       возвращающие функции
                                   print := |Obj o->Str| { prefix + o.toStr }




четверг, 24 июня 2010 г.
Вывод типов

                       Вывод локальных   mc := MyClass()
                                         s := "this is string"
                         переменных      duration := 1day




                    Вывод параметров     intList := [1,2,4]
                   типа для коллекций    strIntMap := ["a":4, "b":5]




четверг, 24 июня 2010 г.
Миксины
                                                mixin FirstLast
                                                {
                                                  abstract Str firstName()
                           Абстрактные поля и     abstract Str lastName()
                                                }
                           методы
                                                mixin Age{ abstract Int age }

                           Методы с             mixin WithImpl : FirstLast

                           имплементацией       {
                                                  Str fullName() { "$firstName $lastName" }
                                                }

                           Перегрузка           mixin MultiInh : WithImpl, Age
                           методов из Obj       {
                                                  override Str toStr() { "$fullName ($age
                                                years old)" }
                                                }




четверг, 24 июня 2010 г.
Мелкие удобства

                           Неявные upcast’ы   Derived derived := base



                              Safe invoke     person?.phones?.first //null if p ==
                                              null


                             Elvis operator   //alias for this == null ? that : this
                                              this ?: that


                  Не нужны () для методов
                                              cap := "a".capitalize
                      без параметров
                     Опциональный return      Int negate(Int arg) { arg.negate }




                             isnot’ keyword   alwaysFalse := "a" isnot Str




четверг, 24 июня 2010 г.
Безопасность


                           Nullable типы

                           Константные классы и члены

                           No shared mutable state




четверг, 24 июня 2010 г.
Nullable types
                                                  class Nullable
                                                  {
                           Every type non-          Void main()
                                                    {
                           nullable by default        Int? nullable := null
                                                      Int nonNullable := 0
                                                      nonNullable = nullable //runtime err
                           Obvious errors are         nonNullable = null //compile err
                           caught by compiler         do3(null) //compile err
                                                      do3(nullable) //runtime err
                                                    }
                           Automatic coercion
                                                      Int do1(Int? arg) { null } //compile err
                           between nullable and
                           non-nullable with          Int do2(Int? arg) { arg } //runtime err

                           runtime check              Int? do3(Int arg) { arg }
                                                  }




четверг, 24 июня 2010 г.
Const types
                                                    class NonConst
                                                    {
             Const classes contain only const         const Int constField
             fields                                    Int nonConstField

                                                        Void mutate()
             Const fields must be set in                 {
                                                          constField = 4 //compile err
             constructor                                  nonConstField = 4 //ok
                                                        }
                                                    }
             Const fields can have only const type
                                                    class Const
             or [List, Map, Func].toImmutable       {
                                                      new make(Int i, Str[] list)
                                                      {
             Static fields must be const                 //implicit call of list.toImmutable
                                                        this.list = list
                                                      }
             List and Maps can be const or            const Str[] list
                                                    }
             mutable



четверг, 24 июня 2010 г.
Actor framework

                           Actors are the only way for multithreading

                           Actor are const classes extending Actor class

                           Actors interchange with const or serializable
                           messages

                           Actors can have private mutable data



четверг, 24 июня 2010 г.
Actor framework
                           using concurrent

                           const class Logger : Actor
                           {
                             new make(ActorPool pool := ActorPool()) :
                               super(pool) {}

                               override Obj? receive(Obj? msg) { echo(msg); return null }
                           }
                           class Actors
                           {
                             Void main()
                             {
                               logger := Logger()
                               logger.send("Hello")
                               future := logger.sendLater(1sec, "Later")
                               logger.send("Now")
                               future2 := logger.sendWhenDone(future, "After later");
                               future3 := logger.sendWhenDone(future2, "After after")
                               future3.cancel

                                   Actor.sleep(2sec)
                               }
                           }



четверг, 24 июня 2010 г.
Мультипарадигменность




четверг, 24 июня 2010 г.
Декларативный стиль

                           a := AddressBook
                           {
                             Person
                             {
                                first = "Ivan"
                                last = "Inozemtsev"
                                phones = [
                                  Phone { num = "+79139494750"; type = PhoneType.cell},
                                  Phone
                                  {
                                    num = "+73833631033"
                                    type = PhoneType.work
                                  }
                                ]
                             },
                           }




четверг, 24 июня 2010 г.
Динамический стиль
  class Dict
                                                    Void main()
  {
                                                    {
    Str:Obj? map                                      dict := Dict(["foo":5, "bar":"str"])
    new make(Str:Obj? map) { this.map = map }         Str a := dict->foo->toStr //"5"
                                                      Str b := dict->bar //"str"
      override Obj? trap(Str name, Obj?[]? args)      Obj o := dict->o //null
      {                                               dict->o = 42
        if(args.isEmpty) return map[name]//getter   }
        return (map[name] = args.first) //setter
      }
  }




четверг, 24 июня 2010 г.
Функциональный
                                стиль
                              persons.findAll |Person p->Bool|
                              {
                                p.first == "Ivan"
                              }.map |Person p -> Phone[]|
                              {
                                p.phones
                              }.flatten
                              .exclude |Phone ph->Bool|
                              {
                                ph.type == PhoneType.work
                              }.map |Phone ph->Str|
                              {
                                ph.num
                              }.each { echo(it) }



четверг, 24 июня 2010 г.
Что включено?

                           Возможность писать build-скрипты на
                           Фантоме

                           Компиляция документации API

                           Встроенные юнит-тесты

                           Встроенный веб-сервер

                           Интерактивная консоль (почти REPL)


четверг, 24 июня 2010 г.
Билд-скрипты
           using build
           class Build : build::BuildPod
           {
             new make()
             {
               podName = "f4builder"
               summary = ""
               depends = ["sys 1.0", "compiler 1.0",
                 "compilerJava 1.0", "javaBytecode 1.0", "f4core 1.0"]
               srcDirs = [`fan/`]
               outDir = `./`
             }
           }




четверг, 24 июня 2010 г.
Билд-скрипты
          class Build : BuildPod
          {
            @Target { help = "Build native JavaFx files" }
            Void javafx()
            {
              log.info("javafx [$podName]")
              log.indent

                 src := scriptFile.parent + `javafx/`
                 dist := scriptFile.parent + `res/javafx/`

                 // start with a clean directory
                 Delete.make(this, dist).run
                 CreateDir.make(this, dist).run

                 // compile and package
                 cmd := ["javafxpackager", "-src",
                   src.osPath, "-appClass", "fan.fwt.Canvas", "-d", dist.osPath]
                 r := Process.make(cmd).run.join
          ...


четверг, 24 июня 2010 г.
документация API

              **
              ** Compare two strings without regard to case and return -1, 0, or 1
              ** if this string is less than, equal to, or greater than the specified
              ** string. Only ASCII character case is taken into account.
              ** See `localeCompare` for localized case insensitive comparisions.
              **
              ** Examples:
              **   "a".compareIgnoreCase("b")    => -1
              **   "hi".compareIgnoreCase("HI") => 0
              **   "b".compareIgnoreCase("a")    => 1
              **
              Int compareIgnoreCase(Str s)




четверг, 24 июня 2010 г.
документация API
               compareIgnoreCase

               Int compareIgnoreCase(Str s)

               Compare two strings without regard to case and return -1, 0, or 1 if this
               string is less than, equal to, or greater than the specified string. Only ASCII
               character case is taken into account. See localeCompare for localized case
               insensitive comparisions.
               Examples:
               "a".compareIgnoreCase("b")           =>   -1
               "hi".compareIgnoreCase("HI")         =>   0
               "b".compareIgnoreCase("a")           =>   1




четверг, 24 июня 2010 г.
Тесты
                    class ParseExprTest : Test
                    {
                    ////////////////////////////////////////////////////////////////
                    // Literals
                    ////////////////////////////////////////////////////////////////

                           Void testNullLiteral()
                           {
                             verifyExpr(ExprId.nullLiteral, "null", |Literal l|
                               {
                                  verifyEq(l.val, null)
                                  verifyEq(l.resolvedType.qname, "sys::Obj")
                               })
                           }




четверг, 24 июня 2010 г.
Веб-сервер
                           class WebHello : AbstractMain
                           {
                             @Opt { help = "http port" }
                             Int port := 8080

                               override Int run()
                               {
                                 wisp := WispService
                                 {
                                   it.port = this.port
                                   it.root = RouteMod
                                   {
                                     routes = [
                                         "hello": HelloMod()
                                       ]
                                   }
                                 }
                                 return runServices([wisp])
                               }
                           }

                           const class HelloMod : WebMod
                           {
                             override Void onGet()
                             {
                               res.headers["Content-Type"] = "text/plain; charset=utf-8"
                               res.out.print("hello world #4")
                             }
                           }
четверг, 24 июня 2010 г.
Как поиграться?
          komaz-mac:margincon ivaninozemtsev$ fansh
          Fantom Shell v1.0.53 ('?' for help)
          fansh> a := [1,2,3,4,5]
          [1, 2, 3, 4, 5]
          fansh> a.map { it * 2 }.map { it.toStr }.sortr
          [8, 6, 4, 2, 10]
          fansh> [1,2,3,4,5].reduce(0) |Int r, Int i -> Int| { r + i }
          15
          fansh> mul := |Int op1, Int op2 -> Int| { op1 * op2 }
          |sys::Int,sys::Int->sys::Int|
          fansh> plusSlot := Int#plus
          sys::Int.plus
          fansh> plus := |Int op1, Int op2 -> Int| { plusSlot.callOn(op1, [op2]) }
          |sys::Int,sys::Int->sys::Int|
          fansh> plus(4, 5)
          9



четверг, 24 июня 2010 г.
Как поиграться?

          komaz-mac:margincon ivaninozemtsev$ echo "#! /usr/bin/env fan
          class Hello
          {
            Void main() { echo("Hello, world") }
          }
          " > hw.fan
          komaz-mac:margincon ivaninozemtsev$ chmod +x hw.fan
          komaz-mac:margincon ivaninozemtsev$ ./hw.fan
          Hello, world
          komaz-mac:margincon ivaninozemtsev$




четверг, 24 июня 2010 г.
Взаимодействие с платформой
                      (на примере Java)
                      using    [java]org.eclipse.dltk.internal.ui.text
                      using    [java]org.eclipse.core.runtime
                      using    [java]org.eclipse.dltk.core
                      using    [java]org.eclipse.ui.progress

                      class ReconcileListener :
                        IScriptReconcilingListener
                      {
                         private AstView view

                           public new make(AstView view) { this.view = view }
                           override Void aboutToBeReconciled() {}
                           override Void reconciled(ISourceModule? module,
                               Bool forced,
                               IProgressMonitor? progressMonitor) {
                             if (module != null) UpdateJob(view, module).schedule
                           }
                      }
четверг, 24 июня 2010 г.
F4 IDE
                           Написана на        Семантическая
                           Фантоме            подсветка

                           Компиляция/        Навигация по коду
                           запуск/отладка
                                              Построение
                           Ссылки между       иерархий
                           проектами          наследования

                           Продвинутое        Показ API-doc’ов
                           автодополнение


четверг, 24 июня 2010 г.
Демонстрация F4 IDE
                        в действии



четверг, 24 июня 2010 г.
Спасибо!




четверг, 24 июня 2010 г.

Иван Иноземцев — Fantom

  • 1.
    Fantom Cross-VM language четверг, 24 июня 2010 г.
  • 2.
    Общие сведения Объектно-ориентированный Статически типизированный Opensource (Academic Free license 3.0) четверг, 24 июня 2010 г.
  • 3.
    Почему Fantom? Мультиплатформенность Отличный язык Удобство “из коробки” (built-in tools) Интеграция с платформой О@#$%ная IDE от Xored :) четверг, 24 июня 2010 г.
  • 4.
    Мультиплатформенность .fan .fcode .js JVM .NET LLVM Parrot четверг, 24 июня 2010 г.
  • 5.
    Достоинства языка Повышение производительности программиста (по сравнению с Java) Страховка от ошибок Мультипарадигменность Низкий порог вхождения (по сравнению с Scala, Clojure) четверг, 24 июня 2010 г.
  • 6.
    Производительность Литералы First-class функции Замыкания Вывод типов Миксины Множество удобных мелочей четверг, 24 июня 2010 г.
  • 7.
    Литералы [1, 3, 5, 7] Списки ["a", ["b", "cd"]] Мапы ["str": "Str", 1: 3, "list": [null, 5]] Str# Типы (reflecion) sys::Str# Str#capitalize `ftp://user001:pass@ftp.com/mydir/myfile.txt` URIs `http://fantom.org` `/Users/ivaninozemtsev/work/fantom` Временные интервалы [1ns, 5ms, 12sec, 3hr, 1day] Диапазоны [1..5, 2..8, 0..<5] четверг, 24 июня 2010 г.
  • 8.
    Функции и замыкания //simple signatures Функции как объекты |->| voidSig := |->| {} |->Int| returnsInt := |->Int| { 42 } Методы содержат |Int a, Int b ->Int| plus := Int#plus.func функции |->| mainFunc := #main.func Функции могут связывать opFunc := |Method m, Int a, Int b| { m.callOn(a, [b]) } mul := opFunc.bind([Int#mult]) //|Int, Int->Int| аргументы plus2 := opFunc.bind([Int#plus, 2]) //|Int -> Int| Замыкания - выражения, Str prefix := "" возвращающие функции print := |Obj o->Str| { prefix + o.toStr } четверг, 24 июня 2010 г.
  • 9.
    Вывод типов Вывод локальных mc := MyClass() s := "this is string" переменных duration := 1day Вывод параметров intList := [1,2,4] типа для коллекций strIntMap := ["a":4, "b":5] четверг, 24 июня 2010 г.
  • 10.
    Миксины mixin FirstLast { abstract Str firstName() Абстрактные поля и abstract Str lastName() } методы mixin Age{ abstract Int age } Методы с mixin WithImpl : FirstLast имплементацией { Str fullName() { "$firstName $lastName" } } Перегрузка mixin MultiInh : WithImpl, Age методов из Obj { override Str toStr() { "$fullName ($age years old)" } } четверг, 24 июня 2010 г.
  • 11.
    Мелкие удобства Неявные upcast’ы Derived derived := base Safe invoke person?.phones?.first //null if p == null Elvis operator //alias for this == null ? that : this this ?: that Не нужны () для методов cap := "a".capitalize без параметров Опциональный return Int negate(Int arg) { arg.negate } isnot’ keyword alwaysFalse := "a" isnot Str четверг, 24 июня 2010 г.
  • 12.
    Безопасность Nullable типы Константные классы и члены No shared mutable state четверг, 24 июня 2010 г.
  • 13.
    Nullable types class Nullable { Every type non- Void main() { nullable by default Int? nullable := null Int nonNullable := 0 nonNullable = nullable //runtime err Obvious errors are nonNullable = null //compile err caught by compiler do3(null) //compile err do3(nullable) //runtime err } Automatic coercion Int do1(Int? arg) { null } //compile err between nullable and non-nullable with Int do2(Int? arg) { arg } //runtime err runtime check Int? do3(Int arg) { arg } } четверг, 24 июня 2010 г.
  • 14.
    Const types class NonConst { Const classes contain only const const Int constField fields Int nonConstField Void mutate() Const fields must be set in { constField = 4 //compile err constructor nonConstField = 4 //ok } } Const fields can have only const type class Const or [List, Map, Func].toImmutable { new make(Int i, Str[] list) { Static fields must be const //implicit call of list.toImmutable this.list = list } List and Maps can be const or const Str[] list } mutable четверг, 24 июня 2010 г.
  • 15.
    Actor framework Actors are the only way for multithreading Actor are const classes extending Actor class Actors interchange with const or serializable messages Actors can have private mutable data четверг, 24 июня 2010 г.
  • 16.
    Actor framework using concurrent const class Logger : Actor { new make(ActorPool pool := ActorPool()) : super(pool) {} override Obj? receive(Obj? msg) { echo(msg); return null } } class Actors { Void main() { logger := Logger() logger.send("Hello") future := logger.sendLater(1sec, "Later") logger.send("Now") future2 := logger.sendWhenDone(future, "After later"); future3 := logger.sendWhenDone(future2, "After after") future3.cancel Actor.sleep(2sec) } } четверг, 24 июня 2010 г.
  • 17.
  • 18.
    Декларативный стиль a := AddressBook { Person { first = "Ivan" last = "Inozemtsev" phones = [ Phone { num = "+79139494750"; type = PhoneType.cell}, Phone { num = "+73833631033" type = PhoneType.work } ] }, } четверг, 24 июня 2010 г.
  • 19.
    Динамический стиль class Dict Void main() { { Str:Obj? map dict := Dict(["foo":5, "bar":"str"]) new make(Str:Obj? map) { this.map = map } Str a := dict->foo->toStr //"5" Str b := dict->bar //"str" override Obj? trap(Str name, Obj?[]? args) Obj o := dict->o //null { dict->o = 42 if(args.isEmpty) return map[name]//getter } return (map[name] = args.first) //setter } } четверг, 24 июня 2010 г.
  • 20.
    Функциональный стиль persons.findAll |Person p->Bool| { p.first == "Ivan" }.map |Person p -> Phone[]| { p.phones }.flatten .exclude |Phone ph->Bool| { ph.type == PhoneType.work }.map |Phone ph->Str| { ph.num }.each { echo(it) } четверг, 24 июня 2010 г.
  • 21.
    Что включено? Возможность писать build-скрипты на Фантоме Компиляция документации API Встроенные юнит-тесты Встроенный веб-сервер Интерактивная консоль (почти REPL) четверг, 24 июня 2010 г.
  • 22.
    Билд-скрипты using build class Build : build::BuildPod { new make() { podName = "f4builder" summary = "" depends = ["sys 1.0", "compiler 1.0", "compilerJava 1.0", "javaBytecode 1.0", "f4core 1.0"] srcDirs = [`fan/`] outDir = `./` } } четверг, 24 июня 2010 г.
  • 23.
    Билд-скрипты class Build : BuildPod { @Target { help = "Build native JavaFx files" } Void javafx() { log.info("javafx [$podName]") log.indent src := scriptFile.parent + `javafx/` dist := scriptFile.parent + `res/javafx/` // start with a clean directory Delete.make(this, dist).run CreateDir.make(this, dist).run // compile and package cmd := ["javafxpackager", "-src", src.osPath, "-appClass", "fan.fwt.Canvas", "-d", dist.osPath] r := Process.make(cmd).run.join ... четверг, 24 июня 2010 г.
  • 24.
    документация API ** ** Compare two strings without regard to case and return -1, 0, or 1 ** if this string is less than, equal to, or greater than the specified ** string. Only ASCII character case is taken into account. ** See `localeCompare` for localized case insensitive comparisions. ** ** Examples: ** "a".compareIgnoreCase("b") => -1 ** "hi".compareIgnoreCase("HI") => 0 ** "b".compareIgnoreCase("a") => 1 ** Int compareIgnoreCase(Str s) четверг, 24 июня 2010 г.
  • 25.
    документация API compareIgnoreCase Int compareIgnoreCase(Str s) Compare two strings without regard to case and return -1, 0, or 1 if this string is less than, equal to, or greater than the specified string. Only ASCII character case is taken into account. See localeCompare for localized case insensitive comparisions. Examples: "a".compareIgnoreCase("b") => -1 "hi".compareIgnoreCase("HI") => 0 "b".compareIgnoreCase("a") => 1 четверг, 24 июня 2010 г.
  • 26.
    Тесты class ParseExprTest : Test { //////////////////////////////////////////////////////////////// // Literals //////////////////////////////////////////////////////////////// Void testNullLiteral() { verifyExpr(ExprId.nullLiteral, "null", |Literal l| { verifyEq(l.val, null) verifyEq(l.resolvedType.qname, "sys::Obj") }) } четверг, 24 июня 2010 г.
  • 27.
    Веб-сервер class WebHello : AbstractMain { @Opt { help = "http port" } Int port := 8080 override Int run() { wisp := WispService { it.port = this.port it.root = RouteMod { routes = [ "hello": HelloMod() ] } } return runServices([wisp]) } } const class HelloMod : WebMod { override Void onGet() { res.headers["Content-Type"] = "text/plain; charset=utf-8" res.out.print("hello world #4") } } четверг, 24 июня 2010 г.
  • 28.
    Как поиграться? komaz-mac:margincon ivaninozemtsev$ fansh Fantom Shell v1.0.53 ('?' for help) fansh> a := [1,2,3,4,5] [1, 2, 3, 4, 5] fansh> a.map { it * 2 }.map { it.toStr }.sortr [8, 6, 4, 2, 10] fansh> [1,2,3,4,5].reduce(0) |Int r, Int i -> Int| { r + i } 15 fansh> mul := |Int op1, Int op2 -> Int| { op1 * op2 } |sys::Int,sys::Int->sys::Int| fansh> plusSlot := Int#plus sys::Int.plus fansh> plus := |Int op1, Int op2 -> Int| { plusSlot.callOn(op1, [op2]) } |sys::Int,sys::Int->sys::Int| fansh> plus(4, 5) 9 четверг, 24 июня 2010 г.
  • 29.
    Как поиграться? komaz-mac:margincon ivaninozemtsev$ echo "#! /usr/bin/env fan class Hello { Void main() { echo("Hello, world") } } " > hw.fan komaz-mac:margincon ivaninozemtsev$ chmod +x hw.fan komaz-mac:margincon ivaninozemtsev$ ./hw.fan Hello, world komaz-mac:margincon ivaninozemtsev$ четверг, 24 июня 2010 г.
  • 30.
    Взаимодействие с платформой (на примере Java) using [java]org.eclipse.dltk.internal.ui.text using [java]org.eclipse.core.runtime using [java]org.eclipse.dltk.core using [java]org.eclipse.ui.progress class ReconcileListener : IScriptReconcilingListener { private AstView view public new make(AstView view) { this.view = view } override Void aboutToBeReconciled() {} override Void reconciled(ISourceModule? module, Bool forced, IProgressMonitor? progressMonitor) { if (module != null) UpdateJob(view, module).schedule } } четверг, 24 июня 2010 г.
  • 31.
    F4 IDE Написана на Семантическая Фантоме подсветка Компиляция/ Навигация по коду запуск/отладка Построение Ссылки между иерархий проектами наследования Продвинутое Показ API-doc’ов автодополнение четверг, 24 июня 2010 г.
  • 32.
    Демонстрация F4 IDE в действии четверг, 24 июня 2010 г.
  • 33.