Saturday 22 October 2011

Compile time generation of Lenses in haxe.

After my previous work around externs generation; I started to think about something that worried me a lot while programming in haXe (it also applies to other languages).


let me put it simply with this snippet:

typedef Toto = {
    var name : String
  }

  var totoNames = arrayOfTotos.map(function (x) return x.name);

As a programmer I am lazy like hell (I often think it's a quality).
I would like to be able not to write the function, I want it to be generated for me automatically so I may write:

var totoNames = arrayOfTotos.map(User_.name_.get);

Also it makes sense to provide a setter the same way we provided a getter.

something like:

arrayOfTotos.map(callback(User_.name_.set, "georges"));

(note that callback is a way to perform partial application in haxe; I personnaly think a special, more general syntax would bring more awesomeness, but at least, we have it :) )


What we've just defined is in fact a Lense.

Here's the actual Lense signature in haXe :

typedef Lense < A, B > = {
    get : A -> B,
    set : B -> A -> A
  }

One interesting thing with Lenses is that we can combine them with some combinators, so let's define some extensions:

class LenseExtension {

    inline public static function mod< A, B >(l1 : Lense < A, B > , f : B -> B, a : A) : A  return
      l1.set(f(l1.get(a)), a)

    public static function andThen < A, B, C > (l1 : Lense < A, B > , l2 : Lense < B, C > ) : Lense < A, C > return {
      get : function (a : A) return l2.get(l1.get(a)),
      set : function (c : C, a : A) : A return
              mod(l1, function (b) return l2.set(c, b), a)
    }

    inline public static function compose < A, B, C > ( l2 : Lense < B, C >, l1 : Lense < A, B > ) : Lense < A, C > return andThen(l1, l2) 
  }

With this we can then compose and build some interesting abstractions:

given this:

var userA : User = {
    age : 6,
    name : "georges",
    say : function (x) return "Beh..." + x
  };

  var userGroup :  UserGroup = {
    users : [userA, userA],
    lead : userA,  
  };

We can do that for instance :

var ageOfUserGroupLead = UserGroup_.lead_.andThen(User_.age_);

and use it like that:

var newGroup = ageOfUserGroupLead.set(5, userGroup);

the interesting bits is that newGroup is structurally equivalent to userGroup but its lead age is modified, in fact all datas are the same but the modified parts; It's an instance of immutable structure 'update'.

This reveals to be particularly helpful when coding against types which have a lot of fields.

Providing an additional, zero cost extension can brings some syntactic sugar:

class LenseSyntactic {

    inline public static function set< A, B >(a : A, l : Lense< A, B >, v : B) : A return
l.set(v, a)

    inline public static function get< A, B >(a : A, l : Lense< A, B >) : B return
l.get(a)
  }

so that you can now write this:

userGroup.set(ageOfUserGroupLead, 5);

It is quite clean as an instance of declarative programming.

Here is how the Lenses are built:

import com.mindrocks.macros.Lense;
  using com.mindrocks.macros.Lense;

  class User_ implements LensesFor< User > {}
  class UserGroup_ implements LensesFor< UserGroup > { }

can't be simpler..


Note than you also have the ability to provide a modification through a function you may apply to a lense (syntactic sugar version):

function complexUserModification(user) {
      var newUser : User = Reflect.copy(user);
      // do you complex stuff
      return newUser;
    }
    
    userGroup.mod(UserGroup_.lead_, complexUserModification);


Performance wise it is comparable to an hand written factorised version; we can provide a lot of speed if/when a limitation of inlining, namely the impossibility to inline functions containing closures is relaxed and another optimization involving removal of temporary unused objects ('escape analysis'?) is done - if possible.

Anyway, for those who want to favor coding speed and then optimize on need; this is a valuable tool.

The code is accessible on my misnamed github repo:
https://github.com/sledorze/haxeExtensionBuilder

Feel free to comment!


P.S.: Specific (think containers) Lenses could/would/will? be generated by hand in a near? future.

Thursday 20 October 2011

Compile time extension generation in haXe.

If you don't know haxe, it's a very flexible, statically typed cross platform language.

I'm currently using it for almost all my jobs.

Recently, I've started using it with nodeJs and needed to create some externs (signatures to use host language objects) for various existing APIs (mongodb for instance) you may find those here:
https://github.com/sledorze/nodejs_externs

Doing so; I've used an interesting haXe capability which is to define several variations of a function using some special syntax (for externs classes and types) while keeping your typing right.


for instance:
@:native("Db")
  extern
  class Db {


    @:overload(function () : Cursor {})
    @:overload(function (callBack : Error -> Cursor -> Void) : Void {})
    public function collectionsInfo(collection_name : String, callBack : Error -> Cursor -> Void) : Void;

    ...
  }

That helps a lot, however, there's currently (haxe evolves quickly) some drawbacks associated with this usage, namely:

- Completion with these alternatives signatures do not work yet (haXe can provide completion information thanks to its lightning fast compiler which is able to return type information of a file position in realtime, as you type..).
- You can't use some advanced haXe niceties (like extensions methods) as this overloading mechanism is implemented as a fallback mode in the compiler, so it can't use this extra information with other features).

Another issue i had specifically with the Javascript target is the difficulty to grasp common javascript patterns you can find in libraries; javascript being so flexible.
One of those is merging objects functionnalities.

A common case is JQuery extensions.
HaXe provides some definitions of JQuery, which is nice, you get completion of the API and it catch your errors ahead of crash.

But at the same time, you cannot use your beloved JQuery plugins as you cannot extends this definition.

In fact, after some discussion on the mailing list, Juraj came with an interesting idea.

Use the compile time macro to create an extern class defining extensions methods in order to provide some inline proxy to the plugin methods. (I promess I've tried to shrink this sentence).

I've decided to implement it as my first haXe macro.
It took less than two hours, and I did not known anything to the API before, thanks to completion and lightning fast compiler, it was a joy to explore, very rewarding.

Let's see some code..

Here's how one would define a small extension (here three methods):

  import JQueryExtension;
  import js.JQuery;

  class MyJQueryExtension implements Extends< JQuery > {
    @:native("val") public function valGet() : Dynamic;
    @:native("val") public function valSet(x : Dynamic) : JQuery;
    @:native("val") public function valFun(f : Int -> Dynamic -> Dynamic) : JQuery;
  }

one need to extends the extension interface and prepend each function with @:native("")

and here's an usage:
  import js.JQuery;
  using MyJQueryExtension;

  class Main {
    static function main() {
      var jq = new JQuery("#someId");

      jq.valGet(); // generates jq.val();
      jq.valSet("content"); // generates jq.val("content");
      jq.valFun(function (i, v) return v); // jq.val(function (i, v) { return v;});
    }
  }
you can see that now the programmer can code against the newly defined API and will have code completion working.

and still have this generated:

Main.main = function() {
    var jq = new js.JQuery("#someId");
    jq.val ();
    jq.val ("content");
    jq.val (function(i,v) {
      return v;
    });
  }

I hope you'll enjoy it; you may find this exemple on my github repository:
https://github.com/sledorze/haxeExtensionBuilder

As always, feel free to ask.. and no trolling please!