My JavaScript book is out! Don't miss the opportunity to upgrade your beginner or average dev skills.
Showing posts with label ES6. Show all posts
Showing posts with label ES6. Show all posts

Saturday, March 30, 2013

Yet Another Reason To Drop __proto__

I know it might sound boring but I really want to put everything down and laugh, or cry harder, the day TC39 will realize __proto__ was one of the most terrible mistakes.

A Simple Dictionary Attack

ES6 says that Object.create(null) should not be affected anyhow from Object.prototype.
I've already mentioned this in the 5 Reasons You Should Avoid __proto__ post but I forgot to include an example.
You can test all this code with Chrome Canary or Firefox/Nightly and the most basic thing you need to know is this:
var n = Object.create(null);
n.__proto__ = {};

for (var k in n) console.log(k); // __proto__ !!!
Object.keys(n); // ["__proto__"] !!!
Got it? So, __proto__ is enumerable in some browser, is not in some other but it will be in all future browsers. Let's go on with examples ...
// store values grouped by same key
function hanldeList(key, value) {
  if (!(key in n)) {
    n[key] = [];
  }
  n[key].push(value);
}
// the Dictionary as it is in ES6
var n = Object.create(null);
Above code simply does not need to be aware of any problems except in older environment that won't work as expected. If the key is __proto__ instead of storing the value there will be most likely an error or the object will inherit from an empty array the moment n[key] = [] will be executed.
In few words, I believe you don't want to fear security and logic problems every single time you set a property to a generic object ... am I correct?
Now imagine some library such underscore.js, has the most common and generic way to create an object from another one, copying properties ...
function copy(obj) {
  var result = {}, key;
  for (key in obj) {
    if (obj.hasOwnProperty(key)) {
      result[key] = obj[key];
    }
  }
  return result;
}

// or if you want ... 
function extend(a, b) {
  for (var key in b) {
    if (b.hasOwnProperty(key)) {
      a[key] = b[key];
    }
  }
  return a;
}
Now guess what happens if you would like to copy or extend that list we had before, where __proto__ will be own property for the n variable and the loop is not checking the key as it should ... the object a, or the new one, will automatically extend an Array and break completely its own expected behaviors ^_^
This is nothing an explicit Object.setPrototypeOf() could cause ... moreover...

Real World Performance Impact

Every utility such lo-dash or underscore should now do this kind of check per each loop if these would like to be considered safe:
function copy(obj) {
  var result = {}, key;
  for (key in obj) {
    if (
      obj.hasOwnProperty(key) &&
      key !== '__proto__'
    ) {
      result[key] = obj[key];
    }
  }
  return result;
}
Now try to investigate in your real-world daily code how many times you change __proto__ compared with how many times you loop over properties ... I give you a test case to compare performance and remember: mobile matters!

Really Hard To Debug

Being a special property in the Object.prototype and not just a function you could wrap and keep under control, in a new scenario where any object could be instanceof anything at any time, the inability to intercept __proto__ calls and changes before it happens will be a painful experience in terms of debugging ... what was that instance before? Most likely, you'll never know ^_^
It must be said some engine makes that descriptor.setter reusable but this is not the case of current V8, as example, neither the case for all mobile browsers out there today.

A Stubborn Decision

What's driving me crazy about this property and all problems it brings, is that regardless there is a possible "speccable" Object.setPrototypeOf() alternative that would not suffer from anything I've described in all these posts, and just as reminder there is already a spec'd and widely available Object.getPrototypeOf() in ES5, TC39 will go on and make the problem a standardized one ^_^
I haven't been able to reason against them regardless examples and reasons ... but you could have fun trying too before it's too late!

Wednesday, January 18, 2012

ES6 Harmony Collections Fast Polyfill

Well, just in case you read RSS and you missed my tweet ... everything you need to know in github repository.
Have fun with Harmony Collections

Tuesday, December 13, 2011

Please, Give Us Back __noSuchMethod__ !

For those who don't know what __noSuchMethod__ is here the quick summary: it was a bloody handy non-standard method able to provide a fallback whenever we invoked an object method that did not exist.

var o = {};
o.__noSuchMethod__(function (name, args) {
alert(name); // "iDoNotExist"
alert([].slice.call(args)); // 1,2,3
});
o.iDoNotExist(1, 2, 3); // will produce above alerts


A Bit Of Background

Well, if you are patient enough, you may consider to read this never-ending post in Mozilla mailing list.
The reason that post is called Proxies: get+fn vs. invoke is because Proxy supposes to be the new way to go able to bring us much more power than we probably ever need ... but hey, this is welcome, while what is not welcome, is that Proxy may not be implemented first, which means browsers vendors should have waited to remove __noSuchMethod__ 'cause right now we may not have a pseudo equivalent, and second, but surely not less important, , Proxy does not provide the same functionality.

The Minified Theory Against The Practice

The main argument from @BrendanEich is that JavaScript has properties only so that o.fn() is the equivalent of o.fn.apply(o).
While this is true with any normal object, this is totally different with __noSuchMethod__.
The equivalent of __noSuchMethod__ for that operation, and behind the scene, is:
  • is there a property in o or its __proto__ called fn ?
    • yes, proceed as usual as if it was o.fn.call(o) and throw error if that property was not callable
    • no, is there a __noSuchMethod__ callback to burn instead of throwing an error due undefined property?
      • yes, perform the current operation: nsm_callback.apply(o, arguments)
      • no, throw an error since property was undefined and obviously not callable
Got it? The equivalent of o.fn() in an environment where __noSuchMethod__ was supported is potentially different from o.fn.apply(o) ... I am 100% sure Brendan knows this before and better than me and this is the reason I don't really get his strongest point.
Once again, o.fn() may be the equivalent of nsm_callback.apply(o, arguments) and not o.fn.apply(o).

The Inexistent Theory Against The Practice

If above "reason" was not enough, I have read even worst in the same thread. I am sorry guys, but sometimes you must be realistic and understand that if a developer does, as example, this:

// de-context fn from o and invoke it
(o.fn)();

// exact equivalent of
var fn = o.fn; // GETTER, no invokation
// and after ...
fn()
// this is a problem? we have same with missing bind then ...

rather than this:

// invoke fn through o as default context
o.fn();
// can we see the difference?

it means that developer has much bigger problems than __noSuchMethod__ inexistent ambiguity, that developer does not even know that __noSuchMethod__ exist ... come on!
Going on and on, another point is that get should be all we need to simulate the __noSuchMethod__ behavior through proxies ... but this is completely misleading!

A Getter IS A Getter

Is that trivial ... if we access a generic object property we are doing nothing different from invoking a getter with such object as property context.

o.whatever;
// look for "whatever" property name in o
// if found returns the "whatever" associated value


o.whatever.call
// nothing change, THIS IS NOT AN INVOKE
// look for "whatever" property name in o
// if found returns the "whatever" associated value
// since the value was a function, the call method is usable
// if whatever was not defined, the call method won't exist

Nobody should ever even consider to use property accessor and expect a __noSuchMethod__ behavior ... that property did not exist, what kind of method would you expect to look for?
call is a property of the Function.prototype so following the accessor/getter logic, nothing is ambiguous here.
Accordingly, lattest example is simply an inexistent mistake that hopefully no developer would ever do ... but you know, shit happens, then we learn, then hopefully we don't repeat same shit.

Other Programming Languages

When it comes to PHP, they perfectly managed to make the behavior not ambiguous through the __call magic keyword in classes definition but no, we decided that in JavaScript we cannot even think to put an invoke to make the life easier and completely NOT ambiguous for all of us ... do we?
I still cannot understand where and what is the ambiguous part if we have an explicit invoke declaration ... maybe something a bit harder to solve behind the scene for these poor JS engines? It could be ... should we all limit JS because of this? I don't think so.

Think About Libraries APIs Migrations

I give you the most basic example, the most used JS library with a fake getter and setter behavior: jQuery.

// jQuery simulation of getters and setters behaviors

// the getter
$("body").html(); // return string with content

// the setter
$("body").html("
whatever
");
// set the string with content

If you want, specially for chainability reasons through the simulated setter, the fact html is a method is convenient for the library but this library is stuck forever behind these two methods.
jQuery, at current ECMAScript status, will never be able to switch gradually to real getters and setters ... why that? A simple example:

$("body").html; // returns the string in jQuery 3000

$("body").html(); // shows a "deprecated warning"
// ... and returns the "html" getter

// implementation example
function setInnerHTML(node) {
node.innerHTML = this;
}
Object.defineProperty($.fn, "html", {
get: function () {
return this[0].innerHTML;
},
set: function (html) {
this.each(setInnerHTML, html);
}
});

// the deprecation warning
$.fn.__noSuchMethod__(function (property, args) {
if (property in this) {
console.log("Warning: " + property + " is not a method anymore");
if (args.length) {
// invoke the setter
this[property] = args[0];
// preserve behavior
return this;
} else {
// invoke the getter
return this[property];
}
} else {
throw "Y U NO READ DOCUMENTATION";
}
});

That's it, we can migrate from two different APIs implementing getters and setters whenever we had a similar behavior and bringing gracefully users to the new usage ... no wa can't!

It Is Not About jQuery

I don't even use jQuery so don't get me wrong, this is not my battle here ... the point is that for another private project I am working on I would like to educate developers to use properties correctly but I understand developers may already got use to invoke methods as if it is normal, even when they are simply looking for a getter behavior.

var o = {
whatever:"cool bro",
__noSuchMethod__: function (property, args) {
console.log("we got a bro-blem here, " +
"don't invoke if you want a getter");
return this[property];
}
};

// so that
o.whatever === o.whatever();

Secially last line of code is apparently impossible to reproduce with Proxies, those that suppose to be the new and best way to go, those that give us control on things rarely needed until now, those that made JS.Next group decide that __noSuchMethod__ was evil and it had to be abandoned.
I really hope that JS.Next will not be non-developer expectations behaviors driven because guys, somebody tries to do cool things with this cool language, and if the reason you drop something is because we are all morons, as example misunderstanding the difference of a referenced property through parenthesis ... oh well ... good luck kkfuture JavaScript ...

How To Solve This

Please put an invoke or even better an invokeProperty, preserving invoke for when the object itself is used as if it was callable, in the current Proxy specifications so that who knows what is doing, can keep doing it and who never even bothered with this stuff, won't be affected at all.
Thank you for listening.

Monday, October 03, 2011

Dear Brendan, Here Was My Question

I had the honor to personally shake the hand of the man that created my favorite programming language: Brendan Eich!

I also dared to ask him a question about ES6 and I would like to better explain the reason of that question.

I have 99 problems in JS, syntax ain't one

I don't know who said that but I completely agree with him.
Here the thing: one of the main ES6 aim is to bring new, non breaking, shimmable, native constructors such StructType, ArrayType, and ParallelsArray.
We have all seen a demo during Brendan presentation and this demo was stunning: an improvement from 3~7 to 40~60 Frames Per Second over a medium complex particles animation based, I believe, on WebGL.

These new native constructors are indeed able to simplify the JS engine job being well defined, known, and "compilable" runtime in order to reach similar C/C++ performances.

These new constructors can also deal directly behind the scene, without repeated and redundant "boxing/unboxing" or conversion, with canvas, I hope both 2d and 3D, and images.

All of this without needing WebCL in the middle and this is both great and needed in JS: give us more raw speed so we can do even more with the current JS we all know!

Not Only Performances

The harmony/ES6 aim is also to enrich the current JavaScript with many new things such bock scopes, let, yeld, destructured and any sort of new syntax sugar we can imagine.
It is also planning to bring a whole new syntax for JavaScript so that the one we known won't be recognizable anymore.

I Have Been There Already

I am Certified ActionScript 2.0 Developer and back at that time, Adobe bought Macromedia and before Macromedia changed the ActionScript language 3 times in 3 years and a half: insane!!!
The best part of it is that everything that was new and not compatible anymore with ActionScript 1, syntax speaking, was possible already before and with exactly same performances: the SWF generator was creating AS1.0 compatible bytecode out of AS2.0 syntax

AS 2.0 was just sugar on top indeed but it was not enough: in order to piss off even more the already frustrated community, ActionScript changed again into something Javaish ... at least this time performances were slightly better thanks to better engine capable to use types in a convenient way.

It must be said that at that time JIT compilers and all ultra powerful/engineered tricks included in every modern JavaScript engine were not considered, possible, implemented ... "change the language is the solution" ... yeah, sure ...

Rather than bring the unbelievable performances boost that V8 Engine, as example, brought to JavaScript in 2007, performances boost that keep improving since that time and almost in every engine, they simply changed the whole nature of the language breaking experience, libraries, legacy, and everything that has been done until that time: this was the Macromedia option, the one that failed by itself and has been acquired, indeed, by the bigger Adobe.

Back in these days, the ActionScript 3.0 community is simply renewed and happy ... now, try to imagine if tomorrow Adobe will announce that ActionScript 4 will be like F#, a completely different new syntax, that most likely won't bring much more performances, neither concrete/real benefits for the community or their end users.

Is this really the way to go? Break potentially everything for the sake of making happy some developer convinced that -> is more explicit or semantic than function ?

CoffeeScript If You Want

As somebody wrote about W3C, why even waste time rather than focus on what is truly needed ?
Didn't CoffeeScript or GWT teach us that if you want a language that is not JavaScript you can create your own syntax and if the community is happy it will adopt the "transformer" in their projects ?
Didn't JavaScript demonstrate already that its flexibility is so great that almost everything can be recompiled into it ?
Emscripten is another example: legacy C/C++ code recompiled out of its LLVM into JavaScript ... how freaking great must be this "JavaScript toy" to be capable of all of this ?
We all know now how to create our own syntax manager, and many developers are using CoffeeScript already and they are happy ... do they need ES6 sugar? No, they can use CoffeeScript, isn't it? Moreover ...
The day ES6 will be CoffeeScriptish the CofeeScript project itself will probably die since it won't make sense anymore.
The day ES6 will be CoffeeScriptish all our experience, everything written about JS so far, all freaking cool projects created, consolidated, and used for such long time demonstrating these are simply "that good" won't be recyclable anymore.
Also, how should we suppose to integrate for cross browser compatibility, the new JS for cooler browsers, and the old one for "not that cool yet" browser?

Continuous Integration

SCRUM teaches us that sprints should be well planned and tasks should be split down in smaller tasks if one of them is too big.
What I see too big here is an ECMAScript milestone 6 which aim is to include:
  • the performances oriented constructors, the only thing truly needed by this community now
  • the block scoped let, generators, destructured stuff + for/of and pseudo JS friendly sugar that can be implemented without problems in CoffeeScript
  • the class statement, over a prototypal language we all love, plus all possible sugar and shortcuts for the function word, once again stuff already possible today but if truly needed, replicable via CoffeeScript

Is it really not posible to go ES 5.3 and bring what's needed with as much focus as possible on what's needed so that the community can be happy as soon as possible and think about what's not really needed after?

Wouldn't this accelerate the process ?

As Summary

Mr Eich, it's your baby, and I am pretty sure you don't need me to feel proud of it. It's a great programming language a bit out of common schemas/patterns but able to survive for years revolutionizing the World Wide Web.
It's also something "everything can fallback into" and I would rather create a Firefox extension able to bring CoffeeScript runtime in every surfed page as long as we can have intermediate releases of these engines, bringing one step a time all these cool features but prioritizing them accordingly with what is missing.

I thank you again for your answer, which summary is: "we are already experimenting and bringing these features in SpiderMonkey ..." and this is great but we are talking about meetings, decisions, and time in the meanwhile to agree about everything else too, specially new syntax.

I am pretty sure that following one step a time we can already have a Christmas present here since I don't see how StructType and ArrayType can be problematic to implement, and eventually optimize later, in every single engine.

These constructors should be finalized in some intermediate specification of the ECMAScript language, so that everybody can commit to it, and every single body would be gradually happier about JavaScript each half year.

In 2013 most likely new powerful CPU/GPU will be able to handle heavy stuff we are trying to handle now ... so it's now that we would like to be faster and it's now that we need these constructors.

I have also shimmed down these constructors already so that incremental browsers upgrades will make these shims useless but performances will be increased whenever these are applied ... a simple example:

var Float32Array = Array, // better shimmed
Int32Array = Float32Array
....

I use similar code already and on daily basis: it does not hurt much, it works today everywhere, and it goes full speed where those constructors are available.

A whole new syntax incompatible with current specifications could be good and evil at the same time plus it will take ages before every engine can be compatible with it ... we all know the story here.

I am pretty sure I am saying nothing new here and I do hope that Harmony will bring proper harmony between what we have now, what we need now, and what we would like to have tomorrow, using projects like CoffeeScript if we really can't cope, today, with this beautiful unicorn.

Thank you for your patience

Tuesday, January 25, 2011

ES6, Harmony, and JS++

... where JS++ is simply metaphoric, in the meaning of "empowered JS" :)

Here the slides I have showed last friday during another team meeting, enjoy!