Ralph – A Dylan dialect that compiles to JavaScript

  • International Lisp Conference
  • 23rd October 2012
  • Bastian Müller
  • ITU Copenhagen
  • @turbolent

Outline

  • Introduction
    • Motivation
    • Problems
  • Solution
    • Language
    • Implementation
  • Conclusion

Introduction

Motivation

  • Application development
  • Web technologies
  • JavaScript only

Why JavaScript?

  • Reach
    • Desktop
    • Mobile
    • Server
  • Features
    • Dynamic
    • Functional
    • Object system

Why not?

  • Difficult to develop large applications
  • Limited
    • Collections
    • Conditions
    • Modules
    • Macros
  • Bad features
    • Hoisting
    • Semantics

Hoisting

            function foo () {
              bar();
              var x = 1;
            }
          

Hoisting

            var foo;
            foo = function () {
              var x;
              bar();
              x = 1;
            }
          

Hoisting – Example

            var foo = 1;
            function bar () {
              if (!foo)
                var foo = 10;
              return foo;
            }
            bar();
          

Hoisting – Example

            var foo = 1;
            function bar () {
              var foo; // = undefined
              if (!foo)
                foo = 10;
              return foo;
            }
            bar(); // ⇒ 10 
          

Solution

  • Compilers
  • Examples
    • CoffeeScript
    • Dart (Google)
    • TypeScript (Microsoft)

Lisp

  • Parenscript (CL)
  • ClojureScript (Clojure)
  • Scheme2JS (Scheme)
  • Gambit-JS (R5RS)

Lisp – Categories

  • Features
  • Implementation complexity
  • Compilation approach

Lisp – Problems

  • Performance
    • Missing optimizations
    • Unnecessary closures
  • Interoperability

Unnecessary closures

ClojureScript

            (let [x (try ... (catch ...))]
              ...)
          
            var x = (function(){
                       try { ... }
                       catch (...) { ... }
                     })();
          

Unnecessary closures

Parenscript

            (setf x (let ((x 1))
                      x))
          
            x = (function () {
                   var x = 1;
                   return x;
                 })();
          

Solution

Ralph

  • Goals
    • Performance
    • Features
    • Expressiveness
  • Inspired by Dylan

Dylan

  • Invented by Apple
  • Based on Scheme, Common Lisp
  • Single namespace, CLOS
  • ALGOL-like syntax
  • Hygienic rule-based macro system

Features

  • S-expression syntax
  • Dylan special forms, standard functions
  • Hygienic procedural macro system
  • Module system

Features

  • Simplified
    • Collections
    • Condition system
    • Numerical tower
  • Single inheritance and single dispatch

Interoperability

  • Usage of native types
    • <object> ⇒ Object
    • <array> ⇒ Array
  • Native calling convention
    • Rest argument
    • Keyword arguments

Module system

  • Only modules
  • Import/export definitions
  • Namespace

Object system

  • Single inheritance and single dispatch
  • Based on prototypes
  • Normal constructors
  • Methods added to prototype

Object system – Example

            (define-class <person> (<object>)
              (name ""))
             
            (define-method hello ((person <person>))
              (format-to-string "Hello, %s!"
                                (get person "name")))
          

Object system – Example

            (define-class <student> (<person>)
              id)
             
            (define-method hello ((student <student>))
              (concatenate (call-next-method)
                (format-to-string " Student #%d!"
                                  (get student "id"))))
          

Object system – Example

            (bind ((john (make <student>
                               name: "John" id: 23)))
              (hello john))
             
            ;; ⇒ "Hello, John! Student #23"
          

Object system – Example

Macro system

  • Procedural, hygienic
  • Inspired by Clojure
  • Quasi-quotation
  • Syntax-quoting

Syntax-quoting

            (bind ((x 23))
              `(y x ,x ,'x))
          
            (foo::y bar::x 23 x)
          

Hygiene

  • Prevent binding of external identifiers
            `(bind ((x ...)) ...
          

Macros – Example

            (define-macro inc! (place value)
              `(set! ,place
                     (+ ,place ,(or value 1))))
          
            (bind ((x 1)
                   (+ -))
              (inc! x)
              x)
            ;; ⇒ 2
          

Scoping

  • No closures necessary
  • Alpha-conversion
(bind ((x (bind ((x 1)) x))) x)
(%bind (x1 (%bind (x2 1) x2)) x1)

Code generation

  • Direct-style
  • Everything as statement
  • Administrative normal form

Administrative normal form

  • Arguments of a function call are trivial
  • Trivial: constant, variable or function
  • Non-trivial computations as bindings

ANF – Example

            (bind ((x (+ (bind ((y 1))
                           (+ y 2))
                         3)))
              (+ (- x 4) x))
          
            (%bind (y 1)
              (%bind (g1 (+ y 2))
                (%bind (x (+ g1 3))
                  (%bind (g2 (- x 4))
                    (+ g2 x)))))
          

Adjusted ANF

  • Change definition of triviality
  • Allow forms not producing statements
            (%bind (y 1)
              (%bind (g1 (+ y 2))
                (%bind (x (+ g1 3))
                  (+ (- x 4) x))))
          

Statement form

  • Move binding values gen. statements to body
  • Add assignments
  • Add explicit return statements
  • Flatten statements

Statement form – Example

            (%bind (x1 (%if ...
                            (%bind (x2 ...)
                              ... (foo x2))
                            3))
          
            (%begin (%var (x1 #f))
                    (%if ...
                         (%begin (%var (x2 ...)) ...
                                 (%set x1 (foo x2)))
                         (%set x1 3))
          

Statement form – Example

            var x1;
            if (...) {
              var x2 = ...;
              ...
              x1 = foo(x2);
            } else
              x1 = 3;
          

Optimizations

  • Performance over size
  • Inlining
  • Tail-call optimization
  • Reduce property access

Conclusion

Future work

  • More optimizations
  • Type checking/inference
  • Multiple dispatch

Code

Thanks!
Questions?