Functional or OOP? a simple case

Lately i am spending some time thinking how I could better organize my thx library. I have many ideas and simplifications in mind but in some areas I still have doubts.

Let’s take the simple interpolation case. As by Wikipedia definition, “interpolation is a method of constructing new data points within the range of a discrete set of known data points”. In programming terms it usually reduces to answer to questions like “if I have the values A and B, respectively the min and max on a scale,  what is the value of C at X percent on that scale and according to a certain equation?”. To further simplify take a scale between 10 and 100, what is the value at 40% using a linear equation?

The code for that can be something like this.

static function linearInterpolation(min : Float, max : Float, k : Float)
  return min + (max - min) * k

There is nothing wrong with this function but if you want to repeat the operation several times there are a couple of hiccups. First the operation computes delta (max – min) too many times; second, and most importantly, it requires that you keep track of variables (min and max) that are needed to define the interpolation but not needed to execute it.

The functional approach to this:

static function linearInterpolationF(min : Float, max : Float)
{
  var delta = max - min;
  return function(k : Float) return min + delta * k;
}

The usage is very simple:

var interpolate = linearInterpolationF(10, 100);
for(i in 0...10)
  trace(interpolate(i/10));

The code itself is clear but their type definitions do not say much:

typedef interpolateFunction<T> = (Float -> Float) -> Float -> T;
typedef interpolate<T> = Float -> T;

T represents the interpolated value that can be literally anything (a Float like in the examples above, or a color or …).

The OOP approach would be something like this:

class LinearInterpolator
{
  var min : Float;
  var delta : Float;
  public function new(min : Float, max : Float)
  {
    this.min = min;
    this.delta = max - min;
  }
  public function interpolate(k : Float) return min + delta * k
}

Needless to say that this version is much more verbose but the signature is in my opinion slightly more readable:

typedef Interpolator<T> = {
  interpolate : Float -> T
}

Usage is not very much different:

var interpolator = new LinearInterpolator(10, 100);
for(i in 0...10)
  trace(interpolator.interpolate(i/10));

So from a user point of view the 2 approaches are not that different in terms of lines of code. It is also worth noting that transforming the OOP approach into the functional one is very very easy:

var interpolate = new LinearInterpolator(10, 100).interpolate;

The opposite is also possible but is a little more cumbersome for the user.

Performance wise the OOP approach wins hands down. Passing functions around is still taxing for all of the Haxe targets (not a Haxe limitation to be clear). In JavaScript, the OOP implementation is about 29% faster than the functional implementation when recycled many times (the same interpolation is reused millions of times) and the difference is even bigger (313%) when the interpolation is used only once. These numbers become even more critical for other platform … for CPP we have even more difference, 548% and 741% faster respectively.

Choosing a programming “style” is obviously not only about performances and in most projects the number above are meaningless; never the less when building a library performances are still an issue because users expect them ;)

Now that callback can be used on any number/position of arguments it is really easy to implement the functional approach from the basic implementation of linearInterpolation:

var interpolate = callback(linearInterpolation, 10, 100, _);

The difference in performances with linearInterpolationF is really minimal and it allows to switch to “functional mode” in a snap.

In this post I obviously oversimplified the case since the interpolation is bounded between two values and it is probably smarter to keep the equation as an argument instead of hard-coded. Interpolating on a path for example might require several points and several equations if curves are involved.

In thx we almost always favor the functional approach + a direct function (like in the first example) but I am not sure it is the “right” way.

What’s your take, what is the approach you like the most?

Haxe 2.09 – WWX 2012

It was really a great pleasure to attend the WWX 2012 in Paris. The talks were extremely interesting and they really showed how much the community is growing. Several factors are contributing to that growth and I am pretty sure that one of these is the amazing development that NME is living and the features that it offers in the mobile department.

The conference was also an occasion for announcements like the new formal spelling of “Haxe” (no more “haXe”). And of course the new Haxe 2.09 that is, in my opinion, one of the best releases ever. Here is my 2 cents about why I like this release so much.

Haxe compiler service

The idea of the Haxe compiler service is really simple. Instead of restarting the compilation process (and the compiler boot strap) on each execution, the compiler is always active in a service waiting for some code to be compiled. It go further than that (otherwise the difference in performances would be minimal), it also keeps cached in memory the intermediate states of the compilation updating only the portions that are subjects to modifications.

My personal benchamarks show the following (after the first run):

project standard compilation compilation service
utest test cases (neko) 310ms (w/o generation 210ms) 110s (w/o generation 10ms)
ReportGrid charts (js) 720ms (w/o generation 590ms) 490s (w/o generation 360ms)

Since the compiler was already very fast, what really makes this feature stand out is that it accelerates auto-completion through -display considerably. I’ve not tested it myself but Nicolas claims x10 faster performances. FlashDevelop is the only IDE so far having adopted this feature transparently but it is not yet in an official build. You can still use it by launching the service this way:

haxe --wait 888

(add -v if you want more detailed information)

And compile you project this way:

haxe --connect 888 build.hxml

Of course you can customize the host/port number and the .hxml file.

JS Improvements

The first most impressive improvement in the JavaScript target is certainly the introduction of --js-modern and the consequent removal of --js-namespace. The new command option enclose the generated code into a closure that prevent the pollution of the global object with all the types defined in your application. Beside that, it adds the “strict mode” directive that can potentially enhance performances in some JavaScript contexts. Also the way that fields are now written in the generated output are more human friendly than before.
Besides the new output works wonder with Google Closure Compiler:

project plain DCE DCE + Closure Compiler
ReportGrid charts 918kb 748kb 569kb
ReportGrid charts w/ –js-modern 924kb 755kb 483kb

Then there is the new -debug implementation. What it does is mapping the source Haxe code to the JavaScript output using a source mapping file. In the browsers that support this very new feature (Chrome so far) you will be able to debug your application directly in Haxe instead of in JavaScript. That means being able to set breakpoints, inspect variable values and call stacks directly in the Haxe code.

revamped Dead Code Elimination (DCE)

My first implementation of DCE had issues under certain conditions. Nicolas took over and revamped it completely making it a lot, lot better.
Using DCE you always have to use some care preventing that portions of the code you are using in your app are not removed by accident. For example if you create an instance by using reflection and the class name, then DCE is probably going to remove that class entirely since its typing is never encountered in the code flow. To avoid that to happen you must use @:expose meta tag at either the type level or at the method level.

Anonymous Objects

The anonymous objects have seen two major improvements, the first is the possibility to use quoted fields to be able to use special characters in your field name and the addition of the optional fields.
The first is very important because now you can simply copy and paste some Json object in your code without having to worry about stripping the quotes. To access the fields with special characters you still need to use reflection.
The optional fields are really powerful for “option objects” (pretty common in the JS world) where you want to be able to define a set of key/value pairs without the need of specifying all of them.
Note that this feature only applies to constant struct, for that reason you can do this:

// assuming that the type of the argument of 'create' is : { ?x : Int, ?y : Int, ?r : Int }
 create({ x : 10, y : 7, r : 4 });
 create({ x : 20, r : 5 });
 create({});

but you cannot do this:

var options = opt(); // where opt is a function returning { x : 20, r : 5 };
create(options); // doesn't compile because not all the fields of options match the signature of the options argument

Unification of Classes

When Haxe was really young there was only one platform (neko) that was capable of accessing the system platform. With the proliferation of the new targets and the expanded possibilities to use the existing ones in different contexts, more and more implementations of the same functionalities have been spreaded over different package names (mainly neko, php and cpp). In Haxe 3 the platform specific API for these will be gone and they will be unified; in 2.09 the types have been already moved to their final destination but shortcuts were left so that the existing code doesn’t break.
The modules affected by these changes are:

Sys (was neko.Sys/php.Sys/cpp.Sys)
sys.FileStat
sys.FileSystem
sys.db.*
sys.io.*
sys.net.*

In thx there were already shortcuts to avoid platform specific packages and I guess I will have to remove them now.

Std.format

This tiny macro is a huge time saver that allows you to simplify things like this:

var s = "Hi "+name+" "+lastname+", your score is "+score;

to this:

var s = Std.format("Hi $name $lastname, your score is $score");

A lot more readable and starting with Haxe 3 it will be applied automatically to all the string definitions compacting the above to:

var s = "Hi $name $lastname, your score is $score";

You can use any Haxe expression inside the string, but if it is more complex than a simple identifier you will have to use the curly brackets format:

Std.format("list length: ${list.length}")

std package for root package

In rare occasions you might have experienced conflicts between types with the same name but that existed in the root package and in a sub-package. Suppose that you have a class def.Type referenced in your code and in the same code you want also to use the type Type. The only way to make that happen would be to create a typedef alias to Type but now you can instead just use std.Type.

haxe.Utf8

For performance reasons the String type is mapped directly to the native implementation of each target platform. The biggest implication of this choice is that the length property and the substr() method can return different results depending on the support of the UTF8 encoding in the targets. With haxe.Utf8 you can reliably obtain a consistent behavior cross-platform.

I have not covered all changes in the new release but only those that make me particularly happy :)

Vector Graphics in the Browser – WWX 2012

I have uploaded my slides (PDF) and the samples from the presentation:

… and remember, circles are bad!

The libraries presented are dhx and thx.

thx: error

The thx.error package contains a bunch of classes to manage errors in your applications. The base class is Error and is a lightweight container for error messages. The nice thing about it is that it separates the message itself from its parameters allowing to format it in a meaningful way:

var error = new Error("invalid import {0:C}", 0.123);
trace(error);
// trace results is: invalid import $0.12

If you provide the needed infrastructure you can also use an instance of ITranslation to deliver your messages:

// Translated Error
var translator = new DictionaryTranslation(ItIT.culture);
translator.addSingular("invalid import {0:C}", "importo invalido {0:C}");
trace(error.translate(translator));
// trace result is: importo invalido € 0,12

I often use to mark my abstract methods so that at least at runtime I have a feedback that the implementation is missing and I do that using the AbstractMethod error class (the NotImplemented error class is functionally equivalent but has a different semantic).

// AbstractMethod / NotImplemented
// in a real world context this will be an instance method and not an inline function

function notImplemented() throw new NotImplemented();
try
{
	notImplemented();
} catch (e : Dynamic) {
	trace(e);
}

The nice thing is that I don’t have to type any message into the constructor because all the info I need are already in there; this is the trace:

method Main.notImplemented() needs to be implemented

Finally the NullArgument error class has a couple of static constructors that helps me check for null arguments. Using macros the argument name is extracted so that you don’t need to type it as a string; that spares you some typing but better yet avoids annoying and error prone repetitions.

// NullArgument
function toUpperCase(text : String)
{
	NullArgument.throwIfNull(text);
	return text.toUpperCase();
}

try
{
	toUpperCase(null);
} catch(e : Dynamic)
{
	trace(e);
}
// trace result is: invalid null argument 'text' for method Main.toUpperCase()

The NullArgument.throwIfNullOrEmpty works similarly but also test for emptiness … this works on Strings, Lists, Arrays (length) and objects (no fields). Note that the type discovery is made at compile time and not at runtime:

// null or empty
function pop(arr : Array) : String
{
	NullArgument.throwIfNullOrEmpty(arr);
	return arr.pop();
}
	
try
{
	pop([]);
} catch(e : Dynamic)
{
	trace(e);
}

// trace result is: invalid null or empty argument 'arr' for method Main.pop()

thx: parsing dates

One of the latest additions to thx is thx.dates.DateParser. It is obviously a date parser, the nice thing about it is that it tries to be fuzzy and to extract a date whenever possible. You can try it yourself here:

Examples of expressions:

  • today
  • now
  • tomorrow
  • next april
  • last sunday
  • three weeks ago plus 5 minutes
  • tomorrow in the evening
  • 6/27
  • 27/6

To produce this tiny demo you just need a bunch of lines of code:

import thx.date.DateParser;
import thx.js.Dom;
import js.Dom;
class Main 
{
  static function main() 
  {
    Dom.select("#date").onNode("keyup", function(n : HtmlDom, _) {
      var t : Text = cast n;
      var result = try {
        Dates.format(DateParser.parse(t.value), "DT");
      } catch (e : Dynamic) {
        Std.string(e);
      }
      Dom.select("#processed")
        .html().string(result);
    });
  }
}

Surely the expression grammar can be improved but it works for my needs right now and it is already very flexible.

thx: basics

In this post I continue to describe the basic functionalities of thx. I’ve decided to put those classes directly in the root because that make them extremely accessible and cases for name conflicts are really low. Having them in the root is perfect if you don’t want to “waste” a line of code for importing a class that you will use just once. For example I always do stuff like:

var values = Ints.range(10);

If you work a lot with math algorithms, the Ints and Floats classes can really make your life easier. Let’s see some examples:

trace(Ints.range(3)); // -> [0,1,2]
trace(Ints.range(7, 10)); // -> [7,8,9]
trace(Ints.range(0, 10, 2)); // -> [0,2,4,6,8]
trace(Floats.range(0, 10, 2.5)); // -> [0,2.5,5,7.5]

I build parsers, encoders and decoders quite often and if that happen to you too you will probably appreciate Ints.canParse(mystring) and Ints.parse. They are really simple functions but help a lot rationalizing your code. The same functions exist in Floats, Dates and Bools (remember that the helper class has the same name as the class it extends but pluralized). The other said of the coin is Ints.format() which convert the value into its string representation. The format function accept formatting options and optionally the reference to a Culture instance (the default one is used if omitted).

Interpolate is also present in most of the basic types. It is really handy for transitions and you can also specify the equation you want to use (default is a linear equation); you can find more pre-cooked equations in thx.math.Equations). So you can interpolate on Strings, Floats, Values, Dates, Arrays and Dynamics … pretty wide options. Where you find the “interpolate” method, usually you find interpolatef too. It works the same but returns a function that takes a float as argument so that you can reuse the same settings over and over. You may wonder what does it mean that you can interpolate over a String or
Dynamic, but it is easy said. Strings.interpolate extracts the floats/integers values from a pair of strings and interpolate those values. Dynamics.interpolate detects the runtime type of the range values and use the function from the corresponding type; if the values do not match a type with a known interpolator an exception is thrown (instance of thx.error.Error).

One of the function I use a lot for debugging is Dynamics.string() that takes any object and transform it into a nicely formatted string. It is surely heavier than Std.string() but it also tries to give a more complete representation of the value passed. Let’s compare both:

var o = [{
	name : "John Doe",
	birthdate : Date.fromString("1972-07-05"),
	score : 7777.7,
	contacts : {
			emails : [
			{ type : "personal", email : "john@example.com" },
			{ type : "work", email : "jd@example.com" }
		]
	}
}, {
	name : "Jane Doe",
	birthdate : Date.fromString("1974-06-09"),
	score : 77777.7,
		contacts : {
			emails : [
			{ type : "personal", email : "jane@example.com" }
		]
	}
}];

trace(Std.string(o));
trace(Dynamics.string(o));

The first trace returns (newline added by hand):

[{
  name : John Doe,
  birthdate : 1972-07-05 00:00:00,
  score : 7777.7,
  contacts : {
    emails : [{
      type : <...>, email : <...> },{
      type : <...>, email : <...> }] } },{
  name : Jane Doe,
  birthdate : 1974-06-09 00:00:00,
  score : 77777.7,
  contacts : {
    emails : [{
      type : <...>,
      email : <...> }] } }]

So you may notice that at some level of recursion the contents are simply striped off; this makes sense in most occasions but I like to have the option to display everything if I have to. This is the output of the second trace (again, newlines added by hand):

[{
  name : "John Doe",
  birthdate : Wednesday, July 05, 1972,
  score : 7,777.70,
  contacts : {
    emails : [{
      type : "personal",
      email : "john@example.com"}, {
      type : "work", email : "jd@example.com"}]}}, {
  name : "Jane Doe",
  birthdate : Sunday, June 09, 1974,
  score : 77,777.70,
  contacts : {
    emails : [{
      type : "personal",
      email : "jane@example.com"}]}}]

So, what are the differences?

  • Strings are quoted (this is handy for guessing the type by just looking at the dump).
  • Dates and numbers are formatted.
  • The whole graph is shown.

That’s all for now ;)

thx : Arrays

In thx there are many helper methods. The convention is that if a class is not meant to be instantiated and its only purpose is to add functionalities to other types than it will be named after the type it enhances but in the plural form. So it is now pretty obvious that Arrays is a helper class for the Array type as Strings is a helper class for String.

So far I am really focused to add (and to improve) features and I am not really worry about file size or performances. Some of the helper classes are pretty dense and refers to other dense definitions which can add some weight to your output. This issue will be addressed at some point by improving thx compatibility with haxe DCE (Dead Code Elimination) or maybe splitting the classes.

Back on the post topic, I’d like to introduce a few of the options you can find in Arrays. So I assume for the following examples that using Arrays; is always in place since that makes the programmer life even easier.

Arrays adds some functions to enhance method chaining, for example you can write:

var arr = [].add(1).add(2).addIf(value > 2, 3).remove(2);

Many methods in Arrays derive from the Lambda class found in the std library but tend to be more flexible and the definitions are also repeated in Iterators and Iterables to make your life easier. Whenever is possible inline is used to prevent adding a new level of indirection. Note that if a method returns a list, it always returns an Array, even if you are using the Iterator or Iterable type. Arrays are pretty fast on all the platforms and are a lot more flexible than the iterators.

// Ints.range(10) returns an array of int from 0 to 9
var arr = Ints.range(10)
  .filter(function(d) return 0 == d % 2)
  .map(function(d,i) return d*d);
// arr is [0,4,16,36,64]

Since hxculture has been included inside thx, you can format many types (and Array is not an exception) to string in a localized fashion. So far you can use 2 formats with array J for “join” and C for “count”.

trace(arr);  //  [0,4,16,36,64]
trace(arr.format("J")); // 0, 4, 16, 36, 64
// the first parameter is for the format of each individual value
trace(arr.format("J", ["D"]));  //  0.00, 4.00, 16.00, 36.00, 64.00
// the second parameter is for empty array
trace([].format("J", ["D", "-"]));  //  -
// the third parameter is the separator
trace(arr.format("J", ["D", "-", "; "]));  //  0.00; 4.00; 16.00; 36.00; 64.00
// the fourth parameter is the max number of elements to display
trace(arr.format("J", ["D", "-", "; ", "3"]));  //  0.00; 4.00; 16.00 ...
// the fifth parameter is for the remaining elements after max
trace(arr.format("J", ["D", "-", "; ", "3", " and more"]));  //  0.00; 4.00; 16.00 and more

trace(arr.format("C"));  //  5

You can also create a format function using var f = Arrays.formatf("J", ["D"]); and after that f([1,2,3]);

Functions like .all()/.any() permits to check if all or at least one of the elements of the array matches a certain rule. The rest of the functions in Arrays are pretty obvious to catch but if you have any doubt I will be glad to five more insights.

thx: color

thx is really growing fast and since it is not yet documented I want to start giving users some hints on the classes included.

The thx.color package is the first set of features I will introduce since the API is pretty stable and I use it a lot.

Creating a color from its channels is really easy:

var color = new Rgb(255, 0, 0); // RGB values are integers from 0 to 255

Of course you can use alternatives to create a Rgb color:

color = Rgb.fromInt(0xFF000);

or

color = Rgb.fromFloats(1.0, 0.0, 0.0);

… but if you are as lazy as I am you can use:

color = NamedColors.red;

or even

color = Colors.parse("red");

Note that Colors.parse() will try everything to find a matching color, infact you can pass a:

  • color name, as defined in NamedColors; names with spaces are accepted aswell (ei: “dark sea green“)
  • css color: #ff0000
  • rgb definition: rgb(255,0,1)
  • hsl definition: hsl(0,1,0.5)
  • cmyk definition: cmyk(0,1,1,0)

Other than Rgb you can define colors in the following colorspaces: Hsl, Grey, Cmyk

I find Hsl particularly useful when you want to create smooth interpolations:

using thx.colors.Hsl;
// ...
var midcolor = Hsl.interpolate(NamedColors.red.toHsl(), NamedColors.blue.toHsl(), 0.5);

If you want to recycle the interpolation and generate an array of colors you can use:

using Arrays;using thx.colors.Hsl;
// ...
var f = Hsl.interpolatef(NamedColors.red.toHsl(), NamedColors.blue.toHsl()),	len = 10;
var colors = Ints.range(len).map(function(_, i) return f(i / (len-1)));

The interpolate/interpolatef methods in Colors will do the same but starting from string definitions.

This can be very handy when you want to interpolate a CSS color. The Rgb.contrast/constrastBW methods are also pretty useful. The former will try to find a pastel color that contrasts with the passed one while the latter will always return white or black. The algorithm of contrastBW uses the grey equivalent of the passed color to estabilish the better contrast for the human vision.

ufront/uform/thx demo from haxecon 2011

Eventually I’ve found the time to put everything together and here come my demos from haxecon 2011.

You can play with it live or you can download the project and compile/run it on your machine.

To compile the project you must have installed through haxelib the following libraries (be sure you are using the correct version because the API will probably change before the 1.0 release):

Note that uform is included in the project and you don’t need to install anything for it.

To run the example on your machine you will probably have to tweak a couple of things:

  • Main.hx: if you use mod_rewrite you will have to create your .htaccess file and change the parameter in the Config constructor from “false” to “true”. Also, if you run the demo from a subfolder different then demo you will have to change that parameter too; if you plan to run in root just put “/” in the path argument.
  • demo/Config.hx: Change your connection settings for your Mysql database and be sure to create a table in the DB with the structure described in the same file.

The project is divided into 3 separate projects:

  • web-pages (both php and neko), use the haxecon.php.hxml or haxecon.neko.hxml to compile
  • colors example page (js), compile using haxecon.d3colors.hxml
  • d3.js port examples (js), compile using haxecon.d3examples.hxml

The live demo on this website is running on neko which is way faster than the php version.

haxecon 2011

The haxecon 2011 has been an amazing experience. Finally giving faces to many haXe users has been incredible.
I attach here my slides in case someone is interested. I’ve just release on haxelib thx, ufront and erazor. uform will have to wait because it is still moving too fast (or too slow, it is really a matter of points of view).

I will also attach the code of my demo soon enough.

p.s. Wow … a post after more than one year.