Referencing `super`

Christoph Martens cmartensms at gmail.com
Wed Aug 6 01:30:20 PDT 2014


On 06.08.2014 06:38, Rick Waldron wrote:
>
>
> On Tuesday, August 5, 2014, Domenic Denicola 
> <domenic at domenicdenicola.com <mailto:domenic at domenicdenicola.com>> wrote:
>
>     I sympathize; I have always found the fact that bare `super()`
>     works to be confusing.
>
>
> When a bare super() call appears in a method (whether constructor or 
> not) it can only have _one_ _meaning_ and that's a call to a method of 
> the same name in the parent class. This isn't particularly innovative: 
> John Resig's Simple JavaScript Inheritance[0]—arguably one of the most 
> widely used (many clones, forks and spin-offs exist) "abstract class" 
> techniques—provides `this._super()` which does the same thing that ES6 
> super() does. This pattern existed before and has been repeated 
> throughout many libraries that have stood out over the years: 
> Prototype, Dojo, Ext.js and certainly others. CoffeeScript implements 
> super() this way as well.
>
>
> Rick
>
>
> [0] http://ejohn.org/blog/simple-javascript-inheritance/
>
>
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss

I wonder why you chose that way in the spec. An issue I can see here is 
that mixin-based inheritance on a per-method basis won't work properly 
as expected.

In my game engine lycheeJS, I'm using a mixin based inheritance to allow

a) inclusions based on feature detection (html, nodejs, v8gl, etc.)
b) inclusions in a specified order (a la a extends b extends c)
c) overwrites of your method with super calls to both via direct 
b.prototype (or c.prototype) access
d) mixin based includes that allow inclusions _of single methods_ of 
other classes


Simplified Example:

var a = function(settings) {
   // moar stuff
   b.call(this,settings);
   c.call(this,settings);
};

a.prototype = { render: function() {
   c.prototype.render.call(this);
   doCustomStuffInBetween();
   b.prototype.render.call(this);
}};

The last reasons (c, d) are very important to my game engine, because it 
allows inclusion of single "public" methods. For example, you can reuse 
a 2D render() method of a ui.State for rendering the UI layer, then draw 
something in 3D on top of it via the game.State.

To access those namespaces properly, I have to create all definitions 
inside a closure with "dynamic" arguments. For example:

lychee.define('lychee.Renderer').exports(function(lychee, global, 
attachments) {});
lychee.define('game.Renderer').exports(function(lychee, game, global, 
attachments) {});

That allows me some essential things for the engine concept:
a) every definition can be exported in a sandbox
b) theoretically sandboxes of supports() (feature detection callbacks) 
are possible with new Proxies, currently they have to be executed global 
(different story of detecting type-based access to properties that are 
not existing at runtime and need to be dispatched)
c) every definition can be serialized as a string and deserialized 
later, in sandboxed state without requiring access to global properties
d) global accesses to properties or bound variables from outer scopes 
are easily traceable via try/catch
e) global can be faked, it is not existing and not "window", it's a 
reference to lychee.Environment's global property.


An example of this mixin-based inheritance usage can be found here:

https://github.com/LazerUnicorns/lycheeJS/blob/development-0.8/projects/boilerplate/source/entity/Circle.js#L99

PS: If you are curious, install lycheeJS via README.md and run the 
localhost:8080/projects/boilerplate. Then call 
lychee.environment.serialize(); which creates the JSON that is 
deserializable (and injectable) at runtime.


Also, what is *REALLY* important (I can't stress that enough). 
JavaScript has a huge bonus when being compared to other programming 
languages. Namespaces are just objects in global scope that can exist at 
runtime, not necessarily at compile time or definition time. Access to 
lychee.game.Main is just new 
lychee.Environment().global.lychee.game.Main. The advantage here is that 
global can be faked as a sandbox and can be isolated to trace errors 
occuring on a per-definition base at runtime. (Namely remote debugging 
and remote code injection via websockets)

This leads to the possibility of inclusion of different libraries under 
a _different namespace_. All libraries think they have say the "game" 
namespace, but in fact, you can include them in a different project 
under a custom namespace. Every library, if sandboxed, will never 
pollute the "global namespace".

These features were the killer decision for me to use JavaScript as a 
game engine base, otherwise I probably would've used Lua (I'm honest).

I would recommend having those listed features in mind when talking 
about super() and namespaces, because the current spec still will 
prevent me from using native "class" keyword in JavaScript.

If newbies ask me if they should use classes, I say no to them, because 
I still think the featureset of a mixin-based inheritance (leading to 
fancy prototype copying and sealing) is still better.


Cheers,
~Christoph

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20140806/7e327116/attachment.html>


More information about the es-discuss mailing list