LinkedInAttic/Fiber

Proposals

Closed this issue · 4 comments

I have two proposals for the improvement of the coding style:
1.) getting rid of the return statements in every class definition
2.) simplifying the base method calls, by replacing
the following statement -> base.method1.call(this, x, y);
with a new one for instance -> base.method1(x, y);

Thanks for the ideas. Can you give an example of the benefit this would have? Would this make Fiber easier to use? Faster? Or, is it just stylistic?

Hi, I believe, this is easier to code, easier to read. We could ask the other way around, why to put additional return statement to each class and why to add "this" to each base method calls.

Before I explain my reasoning, note that proposals 1 and 2 are mutual exclusive. You cannot successfully have them both (unless of course you introduce method overloading and other similar practices).

(1) Getting rid of the return statements in every class definition.

If we were to remove the return statement, we'd have to redesign the inheritance model to work similarly to Backbone's:

var Animal = Fiber.extend({
    method1: function(){}
});

var Dog = Animal.extend({
    method1: function(){
        // Call the parent method
        Animal.prototype.method1.call(this);
    }
});

As you can see above, it means that the consumer of the library would have to explicitely invoke Animal.prototype whenever the super's method needs to be called. Fiber, instead, sugars this redundancy for you by passing in the parent prototype to the child prototype. However, this can only be done if the .extend function takes in a function, which in turn must return some object literal, and thus have access to the parent prototype:

var Animal = Fiber.extend(function() {
    return {
        method1: function(){}
    }
});

var Dog = Animal.extend(function( base ) {
    //  The object literal below defines the prototype, and since it's in a function, 
    //  we now have access to `base`
    return {
        // Override base class `method1`
        method1: function(){
            // Call the parent method
            base.method1.call(this);
        }
    }
});

There's really no compromise with this. It's either we explicitly call the <parent>.prototype and not have a return, or use base and have a return.

(2) Changing Base.method1.call(this, x, y) to base.method1(x, y)

To be able to do this, you'd have to explicitly redefine every method of the parent's prototype, dynamically, to be executed with a new context. This is a relatively nasty operation, as this is a property of the execution context, thus its value is determined once we enter the context, which means that if we were to support this, every function in the prototype would have to be wrapped within another function (and contain a reference to this), and thus every call to a method would actually invoke two functions.


Proposals 1 and 2 would require a merge of John Resig's class to Backbone's extend, which goes against the spirit of Fiber. We want to provide enough of a sugary and consisted inheritance structure as close as possible to native prototypal inheritance without having negative effects on performance. We don't want to create a roundabout way of executing functions which, although prettier to the consumer, would result in slower performance (think gaming use cases).

Thanks for clarifying. I was also wondering why the return statement was necessary and this makes it perfectly clear.

I agree with the statement in the footer "as close as possible to native prototypal inheritance". I think this is not only essential for performance, but also for helping to educate JavaScript developers that we don't need a classical object oriented abstraction in order for us to have easy to use, efficient, flexible (and dynamic) inheritance structures in JavaScript.

I think this would make a worthy addition to the documentation too.