Friday, June 26, 2015

Anonymous method overloading

A few weeks ago I learned about Knockout.js which is a very lightweight JavaScript MVVM library. It contains of some basic features which you can read about on their home page if you are interested.

I quickly was amazed how great their concept of observables works (I love design patterns on steroids). However JS is very different from Delphi code so my first version had them declared like this:
type
  IObservable<T> = interface
    function GetValue: T;
    procedure SetValue(const value: T);
    property Value: T read GetValue write SetValue;
  end;
So working with them looked like this:
var
  o: IObservable<Integer>;
begin
  ...
  Writeln(o.Value);
  o.Value := 42;
That worked quite well but especially with more and more of these observables in my viewmodel that .Value all the time became annoying.

Because in JS functions are first class citizens you can treat them differently so in knockout if you call o() it returns the value of the observable and if you call o(42) is sets the value of the observable.

Could Delphi do the same? We know anonymous methods so we could make our IObservable<T> an anonymous method. But we can make it either a function or a procedure - not both. Yes, we can!

Anonymous methods are implemented as interface. So in fact TFunc<T> is the same as an interface with a method returning T. And that method is called Invoke. We can even inherit interfaces from an anonymous method type making them an anonymous method themselves. However the compiler prevents you from calling a method on them because in Delphi the parentheses are not required for a call. So what if we inherit from TFunc<T> and add an overload to Invoke?

We now have a type that looks like this:
type
  IObservable<T> = interface(TFunc<T>)
    procedure Invoke(const value: T); overload;
  end;
Now we can write code like this:
var
  o: IObservable<Integer>;
begin
  ...
  Writeln(o);
  o(42);
Now that might look a bit strange at first but once you understand the concept this is really amazing.
For more information on my KnockoutJS inspired prototype check out the Knockoff project on Bitbucket. It contains some basic examples and tests to show how the observable dependency tracking works and how they can be used to do binding on UI controls. Though keep in mind that it is only a research project so far - but showing much potential.

Please let me know what you think.

No comments:

Post a Comment