Function.create
Katelyn Gadd
kg at luminance.org
Mon Jun 16 00:06:49 PDT 2014
What's the current status on proposals for Function.create?
At present the inability to set a prototype on a Function instance is
a real hindrance to creating objects that are both new()-able and have
properties. The same goes for creating callable objects that happen to
have properties or methods.
The two existing workarounds - __proto__ and proxies - are apparently
a serious hindrance to optimization capabilities and the latter also
increases code complexity considerably.
I have heard hints that at some point it might be possible for an ES6
class to inherit from Array or Function, which implies being able to
create a Function with a custom prototype. Is this planned to be the
case? I'm told that neither V8 or SM support this at present.
I've been researching this because the inability to create a Function
instance with a prototype is one of the largest handicaps that remains
for JSIL. I think the same will be true for any compiler that tries to
interop with native JavaScript while providing more robust type system
semantics. Not only does it produce an enormous performance penalty,
but it complicates the runtime code considerably.
The __proto__ workaround would involve creating the prototype for the
function first (as a stand-alone object), then setting it onto the
Function instance after creating it. Sadly my research suggests that
this is a full, permanent deopt of the Function instance and that it
is not likely that this will change anytime soon.
The issues with using a proxy to enable this should be self-evident;
if people have a strong suspicion that this will become fast in the
near future, that would be great to hear. From a design perspective
using a proxy to solve this seems like using an enormous hammer to
lightly tap on a bent nail.
A summary of my particular scenario: I have a cyclic dependency
problem when initializing object graphs that contain Functions. For
Object, it is possible to break these cycles by first constructing the
prototype (and passing it around/storing it) in order to temporarily
break the cycle, before you finally attach the fully-initialized
prototype to its destination object. This is not possible with
Function, because you must construct your function body *before*
setting properties onto the Function instance. This makes the
construction of various cyclic object hierarchies impossible. The
'temporary prototype' solution becomes difficult because in this
scenario, the properties literally have to be transplanted (manually,
via assignment) from the old object onto the new, which means that any
retained references to the 'placeholder' object will become out of
sync with the new object. Using the placeholder object as the
prototype of the new Function allows these two to remain in sync, and
effectively be identical (other than the ability to new() them).
The .NET type system is a good example of type hierarchies that form
an interconnected graph. Representing these type objects as callables
(to enable 'new') means we have to be able to create a type's
constructor before we have created and defined the type, and this
means that the only way to define that constructor is for it to be a
delegating constructor that calls .apply() on a function reference
from a closure that is initialized later. Thus far it has been
impossible for any JS runtime to optimize these delegating
constructors (I've tried lots of variations), and they seem to also
prevent the creation of densely packed, optimized shapes for
instances. The result is that this pattern produces increased memory
usage and reduced performance.
Function.create would enable considerably simpler JS for this scenario
and similar scenarios. I suspect other languages that try to integrate
natively with JS (vs creating your own isolated bubble like
emscripten/asm.js) will face similar issues. The other compilers I've
seen that tackle this solution efficiently do so by abandoning the
'new' keyword in favor of magic methods, which I consider a poor
solution.
Thanks,
-kg
More information about the es-discuss
mailing list