Sunday, May 04, 2014

Fixing Java Nashorn __proto__

update these guys react quickly, bug tracking here promptly opened by Jim Laskey: thank you!
all right, you might think __proto__ is my obsession but for f*$#k sake not a single engine got it right so far ... and it's perfectly spec'd in ES6 too so I don't know what is with nashorn here ...
// how to fix nashorn
Object.defineProperty(
  Object.prototype,
  '__proto__',
  {
    configurable: true,
    get: function () {
      return Object.getPrototypeOf(this);
    },
    set: function (proto) {
      Object.setPrototypeOf(this, proto);
    }
  }
);

Are You Asking Why?

Here the answer: nashorn is broken, since it does not expose __proto__ quirks anywhere.
'__proto__' in {} is false
Object.getOwnPropertyNames(Object.prototype).indexOf('__proto__') is a -1 negative
Object.getOwnPropertyDescriptor(Object.prototype, '__proto__') is null
Basically even most common basic features detections for '__proto__' are screwed, so that not a single library can trust its own code ... how cool is that ...

Broken null Objects Too

The worst of the worst comes with null objects, where the infamous property makes dictionaries pointless, not secure, and unreliable ... I start thinking the web world was not even ready for dictionaries, it's taking forever to have a reliable one
var o = Object.create(null);
// it's a null object
// nothing should affect it
o.__proto__ = [];

// but nashorn is brilliant
// as old Android 2.1 phones here
o instanceof Array; // true
Congratulation, you never understood what was the purpose of __proto__

Quick Specs Recap

So, since it's apparently the first rocket science problem ever, here a quick summary of how stupidly simple is the __proto__ spec:
  1. if it's a literal expression, not wrapped in quotes, it defines inheritance at runtime: {__proto__:[]} which is an instanceof Array VS {"__proto__":[]} which is just valid JSON and won't even affect inheritance
  2. if accessed through the Object.prototype, where whatever object that inherits from null should NOT be involved, and where __proto__ has not been defined as own property, it behaves as described in the first snippet I've created to fix nashorn
  3. everything else is an epic fail ... seriously, no difference between o.__proto__ or o["__proto__"] and similar madness, if it inherits from Object.prototype and the configurable behavior hasn't been deleted it passes through that get/set logic ... that's really it!
So please fix this madness once for all ... it's about reading specs and implementing them properly, even if Appendix B of whatever status ES6 is ... or GTFO!
</rant>

4 comments:

Jim Laskey said...

To be honest, we wanted to get rid of __proto__ altogether and require people to use Object.create, ‎Object.getPrototypeOf() and Object.setPrototypeOf(). Instead we were bullied into supported the deprecated __proto__. I'll submit a bug on your behalf.

Jim Laskey said...

https://bugs.openjdk.java.net/browse/JDK-8042364

Andrea Giammarchi said...

thans Jim, as mentioned alredy in the tweet I apolgy for the tone of this post but this property is wrong since ever, disaster prone, and seing this badly implemented in new engines as nashorn is hurts my feeling ... duktape simply respected ES 5.1 specs, as example, and __proto__ indeed is nowhere in there.

I don't know who bullied nashorn for this but clearly had no idea what was __proto__ about.

In node.js they use it to extend natives because they have no Object.setPrototypeOf ... no other reasons, really.

Thanks for your understanding and prompt support.

Jim Laskey said...

Fixes will make 8u20. The Avatar.js (Node) team will patch the Node sources (locally) to expect the correct behaviour.