Tinkerbell

Haxe on Wings

But first

A few thoughts on programming

Warning

Don't believe me.

Not even when I'm (mis)quoting clever people.

Don't believe them either.

Try things for yourself.

Particularly those that seem revolting at first.

We suck at this

Don't think so?

Would you seriously trust a bridge, let alone an airplane, built the way we build software?

We are not engineers!

That's a worthy goal, but it is far ahead.

There are no shortcuts.

Engineering comes from ingenuity.

Keep the fun

I think that it's extraordinarily important that we in computer science keep fun in computing. [...] We began to feel as if we really were responsible for the successful, error-free perfect use of these machines. I don't think we are. I think we're responsible for stretching them, setting them off in new directions, and keeping fun in the house. [...]

Methodologies

They are orthogonal to Programming

The ones that are about programming often cause more problems than they solve.

The ones that add value are about communication.

Embrace Nothingness

List of all proven methods to avoid bugs in code:

  1. Don't write code.
  2. End of list ...

Do not ruin the empty slate!!!1!1!

The codebase becomes a terrible mess all by itself.

No need to accelarate the process.

Leave yourself the room to maneuvre.

Trust your fellow programmers

  • Trust in their willingness to learn and grow.
  • Trust in their ability to complement the code you write. (Even if you are 100% positive they are heretically superstitious, that doesn't mean they are incapable)
  • Don't impose decisions on them.
  • Don't consider yourself smarter. It gives you the wrong perspective.
  • Never be afraid to ask.

YAGNI / KISS

It seems that perfection is attained not when there is nothing more to add, but when there is nothing more to remove.
Antoine de Saint Exupéry

YAGNI

  • Implementing things that may be useful later is a form of premature optimization.
  • Adding what you need to a lean system is easier than bending a huge system that does almost but not quite what you need to do when you actually need.
  • Be aware of adding implicit assumptions to your design. Example: HTTP

NOT KISS

Problem: You need to cut and pinch

KISS

Problem: You need to cut and pinch

Simplicity

  • Easy and simple are two different things. Simplicity is hard to achieve and simple things are not necessarily easy to use. Just easy to to reason about.
  • When in doubt, keep things small.
  • Oversimplification is to simplicity what perfectionism is to perfection.

In a nutshell

There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies, and the other way is to make it so complicated that there are no obvious deficiencies. The first method is far more difficult.
C. A. R. Hoare

Divide and Conquer

There is evidence to suggest it works.

Also known as:

  • Seperation of Concerns
  • Single Responsibility Principle
The single responsibility principle states that every class should have a single responsibility, and that responsibility should be entirely encapsulated by the class.
Wikipedia

A beginner's mind

In the beginner's mind there are many possibilities, in the expert's mind there are few.
Shunryu Suzuki

Looking at Haxe

Does Haxe deliver on the promise Java failed to keep?

(That's a serious question, but for now let's go with:)

Of course it does!!!

Why?

No short lambdas

What's not in Haxe is as important as what is.

Also:

Bending Haxe

To what end?

What it's not

And never going to be

  • One framework
  • Finished

What it is

A continuous work in progess.

Many small, well documented packages.

See github.com/haxe_tink/

  • tink_core (hx: 529, md: 587 (67%))
  • tink_macro (hx: 1310, md: 303 (36%))
  • tink_lang (hx: 1934, md: 776 (38%))
  • tink_priority (hx: 103, md: 110 (61%))
  • tinx_autospod (hx: 146, md: 15 (30%))
  • tink_template (hx: 809, md: 213 (31%) )
  • More to come ...

Tinkerbell Core

  • Error handling
  • Asynchrony
  • Lazyness
  • Signals
  • And more ...

Philosophy

Composability!!! Composability!!! Composability!!!

See also promhx and msignal.

Example: tink.core.Signal has a map and a filter method. Let's make it pausable!

function pausable<T>(s:Signal<T>) {
  var paused = false;
  return {
    signal: s.filter(function (_) return !paused),
    isPaused: function () return paused,
    setPaused: function (param) paused = param,
  }
}

More composing

typedef Button {
  var clicked(default, null):Signal<MouseEvent>
}

var up:Button = ...,
    down:Button = ...;

var delta = up.clicked.map(function (_) return -1).join(
  down.clicked.map(function (_) return 1)
);

$type(delta);//Signal<Int>

Tinkerbell Language Extensions

  • Trailing argument
  • Short Lambdas
  • Extended and optimized loops
  • Partial implementation (much like traits)
  • Syntactic forwarding
  • Function options
  • And more...

Usage

Use in any class with implements tink.Lang.

Extended syntax is applied to the class and all subclasses.

class Point implements tink.Lang {
  public var x = (.0);
  public var y = (.0);
  @:calculated var length = Math.sqrt(x * x + y * y);
}

Trailing arguments

Do you hate it to have an expression end with })]})?

Mysql.connect() => {
  database : 'test',
  user : 'user',
  password : 'password',
}

Short Lambdas

[] => 4;               
[x] => 2 * x;          
[x, y] => x + y;       
x => 2 * x;            

@do body;              
@do(x, y) trace(x + y);

@f value;              
@f(x, y) (x + y);
function () return 4;
function (x) return 2 * x;
function (x, y) return x + y;
function (x) return 2 * x;

function () body;
function (x, y) trace(x + y);

function () return value;
function (x, y) return x + y;

And more Short Lambdas

switch _ {}     
switch [_, _] {}

@do switch _ {} 
@f switch _ {}
function (x) return switch x {}
function (x, y) return switch [x, y] {}

function (x) switch x {}
function (x) return switch x {}

Nice example

myButton.clicked.handle() => @do {
  trace('clicked!!!');
}

http.load(someUrl).handle() => @do switch _ {
  case Success(data): trace('loaded $data');
  case Failure(error): trace('ERROR: $error!');
}

Extended loops

for (i += .5 in 0...100) {}
for (i -= .5 in 100...0) {}

for ([b in bananas, m in monkeys]) m.eat(b);
for ([b in bananas, m in monkeys || monkey[0]]) m.eat(b);

for (key => value in map) {}

for ([m in monkeys, i++]) {}

Optimized loops

@:tink_for({ 
  var i = 0, a, l;
  {
    a = untyped __call__('array_values', @:privateAccess this.h);
    l = untyped __call__('count', a);               
  }
}, i < l, a[i++])
function iterator():Iterator<T>;
  • Usually a speed up of factor 1.5 to 4 for loops
  • Factor 40 for lists on flash and 30 for string map keys on java

Partial implementation

Interfaces can have implementation

interface Enumerable<T> implements tink.Lang {
    @:calc var length = fold(0, function (count, _) return count + 1);

    function fold<A>(init:A, calc:A->T->A):A {
        forEach(function (v) init = calc(init, v));
        return init;
    }
    function forEach(f:T->Void):Void 
        for (v in this) f(v);

    function map<A>(f:T->A):Array<A> {
        var ret = [];
        forEach(ret.push);
        return ret;
    }
}

Partial implementation

Partial implementation can have dependencies

interface Enumerable<T> implements tink.Lang {
  /* ... */
  @:usedOnlyBy(iterator) 
  var elements:Array<T> = [];
  @:usedOnlyBy(forEach)
  public function iterator():Iterator<T> {
      return elements.iterator();
  }  
}

Syntactic forwarding

class Stack implements tink.Lang {
  @:forward(push, pop, iterator, length) var elements:Array;
  public function new() {
    this.elements = [];
  }
}

Function options

function connect<T>(                      
  args = { 
    host: 'localhost', 
    port: 3306, 
    'database': 'test', 
    username: (_ : String), 
    password: (_ : String) 
  }
) {
  return Mysql.connect(args);
}

Tink Auto SPOD Extension

Automatically connects. Creates missing tables and adds missing columns. Initializes SPOD.

Usage: -lib tinx_autospod tinx.AutoSpod.use() (See #3037)

Configuration through dbconfig.uri in working directory

mysql://user:password@host:port/dbname

sqlite:path/to/file.db

alias:path/to/directory

Tink Template

Largely haxe.Template compatible compile time template language with rich syntax, including switch, while, for, var, function.

Templates become true Haxe classes on the fly, that can implement interfaces and extend classes.

Usage: -lib tinx_autospod tinx.AutoSpod.use()

No support for import and using (see #2868).

Example

//Example.tpl
::static inline var TITLE = 'Awesome blog'::

::static function header(?title = TITLE)::
  <!DOCTYPE html><html><head><title>::title</title></head>
  <body>
::end::

::static function index(posts:Array<Post>)::
  ::header()::
    ::for p in posts:: ::excerpt(p):: ::end::
  ::footer()::
::end::

::static function excerpt(p:Post)::
  ::p.excerpt()::
  <a href="/post/::p.id::">Read more</a>
::end::

::static function doDefault()
  Sys.print(index(Post.manager.all()))
::

::static function main()
  Dispatch.run(Web.getURI(), Web.getParams(), Example)
::
            

Escaping

Just use the type system.

abstract Html {
  public function new(s:String):Void;

  @:from static public function escape(s:String):Html;
  @:from static function ofMultiple(parts:Array<Html>):Html;
  
  @:from static public function of<A>(a:A):Html;
}

The Future

  • More tests
  • More modules
  • More users?
  • More contributors??

Join Now!

Questions?