My JavaScript book is out!
Don't miss the opportunity to upgrade your beginner or average dev skills.

Saturday, February 20, 2010

JavaScript Overload Patterns

Update I have continued with patterns into JavaScript Override Patterns.We all know JavaScript does not implement a native methods overload concept and what we usually do on daily basis is to emulate somehow this Classic OOP behavior.There are several ways to do it, all of them with pros and cons, but what is the best way to implement it?

A common situation

Let's imagine we would like to have a method able to accept different arguments types and return something accordingly with what we received.Usually in Classic OOP an overload cannot redefine the returned type but in JavaScript we can do "whatever we want", trying to be still consistent, so that we can consider us more lucky than C# or Java guys, as more flexible as well.For this post, the behavior we would like to obtain will be similar to the one we can find in jQuery library, one of the most used, famous, and friendly libraries I know.

While the classic get/set concept is boring, old style, and not optimized, the chainability one is really smart, semantic, easy to understand, and bytes saver.As example, compare above piece of code with this one, following comments to understand which part is not that convenient:

// create an instancevar me = new Person();

// set some propertyme.setName("Andrea");// unoptimized operation, a setter// does not usually return anything// we would expect at least the set parameter// as if we did// (me.name = "Andrea")// we could expect true/false// as operations flag// but when do we need a "false"// able to break our code in any case?// throws an error if the operation// was not successful since we cannot// go on with what we expect

// set something elseme.setAge(31);

// we need to rewrite the var name// for every single method// plus we need to write methods with// everytime a prefix: get or set// this is redundant and inefficientme.getName(); // Andrea

If we pass under minifiers and mungers this silly little example, we'll find out that the chain strategy goes from 72 to 56 bytes, while the get/set goes from 76 to 68.As summary, while overload strategies could be adopted in both cases, the example code will use the first strategy to perform the task: "create a Person class and a method able to behave differently accordingly with received arguments"

Inevitably via "arguments"

As is for every scripting language, the basic strategy to emulate an overload, is the lazy arguments parsing.Lazy, because we need to understand for each method call what should be the expected behavior.This is surely a performances problem so even if the topic in this case is overload, we should never forget that sometimes the best way to set or get something, is setting or getting something:

// if we can set something// the internal property is somehow exposed// in any case since it is reconfigurableme.setName("Andrea");me.setName("WebReflection");me.getName();

// againstme.name = "Andrea";me.name = "WebReflection";me.name;

Avoid pointless overheads

Of course getters and setters could be considered safer, but how many times we have spotted code like this?

Above code simply adds overhead for each operation performed against the _stuff property, and what's the point to do it in that way?Unless we don't ensure a type check for each call, above code style over a programming language without type hints could be simply considered an error, since every time we spot a badly implemented design, error is usually the first thought we have.

The Simplest Overload Implementation

Latest code could be already compressed into a single method. We want to perform different operations, accordingly with a generic argument, plus we would like to "kick Java Devs ass" overloading the returned value as well to make chainability possible.

function Person(_name) { // we would like to have a default name this._name = _name || "anonymous";}

Person.prototype = { constructor: Person, name: function (_name) { // what should we do? // if _name is not undefined or null if (_name != null) { // we want to set the name // (eventually doing checks) this._name = _name; // and return the Person instance return this; } else { // nothing to set, it must be a get return this._name; } }};

A simple test case:

var me = new Person();alert([

me.name(), // anonymous

me // magic chain! .name("Andrea") .name() // Andrea].join("\n"));

Where Is The Overload

When we talk about overload, we think about multiple methods invoked runtime accordingly with received arguments.Since as I have said we cannot do this in JavaScript:

all we usually do is to put a lot of if, else if, else, switch statements inside the same method.

Overload Pros

I do believe it's hardly arguable that overloads are able to make code easier to maintain and both more clear and more linear.While strict typed languages do not need to take care about arguments type, scripting languages are often focused about this matter and the code inside a single method could be messy enough to be hardly maintainable or debuggable.In few words, with overloads we can split behaviors incrementing focus over single cases delegating arguments parsing, when and if necessary, in the single exposed entry point: the method itself.

Overload Via Polluted Prototype

The first overload implementation to obtain exactly the same behavior is this one:

Pros

We can "cheat" a little bit in the entry point referencing the this variable to decide which "protected" method we need to call.In my case I don't even mind if _nameGet does not accept an argument, which is still a bad design since the operation is just tricky without a valid reason, but at least we have more flexibility. If we think that every method could have common operations inside, e.g. a User class with a protected this._isValidUser() performed via every other method call, this approach could be considered good enough to split all matters/logics we are interested about.

Cons

Specially for debug, all those faked protected methods could be really annoying. All we want to show/expose are public methods so that a for in loop or a console.log operation, as example, will show just the "public status" of an instance and not every single internal method we are not interested about. Moreover, some "clever" developer could decide to use internals calls but we would like to avoid any kind of critical operation, don't we?

Overload Via Closure

This second approach is able to maintain overload benefits, exposing only what we want:

Pros

A for in loop will pass only the constructor and the public method so that nobody can change, use, or modify its internals. Even other methods cannot access into "name" closure so we are free to use common meaningful name as is as example for both get and set.If at some point every overload needs to perform the same task, we can simply create another function so that this will be shared in the whole closure.

Cons

Somebody could argue that those internal functions are not Unit Test friendly ... at least this was my guess before I talked with a skilled programmer that said: "dude, you should test what you expose and not what is the exposed internal logic. In other words, it's the name method the one you care about, and not what happens inside which will be implicitly tested via 'name' calls".Due to the closure, it is not possible to share across the prototype a single function reused for each call.This is not something truly problematic, since in this case we can always use an outer closure:

Simplest Overload

We can easily deduct that the most common approach to behave differently is the classic method with "everything inside". Under the microscope, performances will be slightly better than every other approach since the number of function calls is reduced. But, we should consider that my example does basically nothing and that in most common cases the whole function body is polluted with large amount of variables, sometimes potentially disturbing (e.g. for (var i, ...)) and we can hardly debug long methods with hundreds of checks and if else there. Of course the example I have chosen does not really represent the perfect scenario where it's evident how much cleaner overloads are against common code style, so in that particular case, I would have chosen the first approach, but this is up to us, and "case per case" dependent.

Polluted Prototype

While performances and semantic could appear a bit better, the compression ratio in this case is the worst one. Moreover, this approach implicitly suffers name clashes problem. We should simply think about chained inheritances, and how many times we could have the same name over different mixins or classes.If we add what we have already understood about Cons, I would define this approach the less convenient one, while it is still probably the most adopted one starting from the classic protected method approach.

Overload via Closure

This approach is already good for its purpose. Not a single compiler can optimize a this reference so I do hope developers will start to get rid of the classic call/apply approach in favor of the self one. THere are no benefits against the polluted prototype, byteswise speaking, but it is still valid all Pros against the latter one.

As we can see, the number of this references inside the overloaded method is reduced to three, rather than N for each private method call. The compression ratio is best one as is the size, except for the basic case.Lots of pros, and "just a matter of style" as cons, I already like this latest pattern!

As Summary

We should always analyze different patterns and pros and cons every time we decide to adopt a strategy to emulate something not truly part of the language nature. This is what I have tried to do in this post, hoping some developers will appreciate it, starting to use some suggestion, or giving me more ;)

@Mariusz get/set in JavaScript are both powerful and slower than direct access.The point is that get/set should be used to manifest a variable, and not as default access method.

Think about an Array length, to emulate it, we should use get/set so that get will return the current length, e.g. count(this.items), while set will eventually drop items or add undefined items.

Above behavior is not possible via direct access, but whatever library that will use get/set without thinking at all why they are using it, will be both bigger, size speaking, and slower, without any valid reason.

get/set with internal direct access, are a total nonsense, if there is no check over inputs when we set the property.

I do like get/set, I don't like bad usage of whatever construct we have in the whatever language we use ;)

@AndreaYeah I like get/set either and I take full advantage of it when I program in language that natively supports them.However in JavaScript for the reasons you pointed I never really considered emulating them, anyway interesting read :)

When I first started reading your post, I wondered how you were going to address method overrides in subclasses. However, you didn't mention this.

I spend a significant amount of my programming effort overriding methods of objects in other people's libraries. If the other developer uses a closure to implement the get/set strategy -- and I need to override the set method to add logic or behavior -- I'll have to rewrite the entire set of functions in the closure. For simple get/set pairs, this is fine, IMHO. However, for more sophisticated situations (containing validation logic or side effects), some additional strategies could be used to allow injection of additional logic by subclasses.

I'm typing on a phone right now. Otherwise, I'd code some examples. Anyway, you'd probably do them more efficiently!

I'm just wondering why you check for _name == null to see if _name have been passed. Because if I want to set name to null / 0 / false ... and so on. May be better to check for === undefined. Or even argument.length == 0;