Quantcast
Channel: weblob.net » thx
Viewing all articles
Browse latest Browse all 7

Functional or OOP? a simple case

0
0

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?


Viewing all articles
Browse latest Browse all 7

Latest Images

Trending Articles





Latest Images