A bit on Object.extend(obj,{...}) vs. obj.{...}
To get started, just a reminder that we can't really compare the two based on
the assumption that the second argument to extend is an object literal as there
is no way to syntactically guarantee that. We have to assume that both
arguments to Object.extend are preexisting object that were created in some
arbitrary manner. EG, we are have to compare Object.extend(obj1, obj2) vs.
obj1.{...}
On Apr 29, 2012, at 10:10 AM, Axel Rauschmayer wrote:
> ...
> Object.extend would automatically invoke Object.defineMethod() (or similar)
> for you, to enable super-references (but I doubt there is much use for them
> in mixins).
Mixin's and inheritance (including) super references are orthogonal concepts.
Some may choose to use only one or the other but they really need to be
composable for for those who need to use them in combination.
The defineMethod point is important. Equally important is the treatment of
private named properties.
To correctly preserve super invocation semantics methods must be processed
using Object.defineMethod when they are copied from obj2 to obj1. For
obj1.{...} this isn't a problem because the "extension object" and its
properties don't preexist. They are just syntax that is processed just like
creating completely new properties on obj1 and the semantic rules for those new
properties are exactly the same as those that would have been used in an object
literal that was providing the initial definition of obj1. There is no copying
semantics of worry about.
One of the syntactic distinctions that is made by obj1.{...} is the difference
between a "method" property and a function valued "state" property. Consider:
//somewhere else in the program
vender.getSomeCallback = function(a,b) {
let cb= function()
{...myWeakMap.get(cb).attachment...this.something(a,b)....};
myWeakMap.set(cb, generateAttachment(a,b));
return cb;
}
//main example
obj1.{
callback: vender.getSomeCallback(x,y),
meth() {
super.meth();
this.callback.call(this.target);
}
Note that .{ sees the callback property as a regular "state" property and
doesn't use defineMethod semantics to create it on obj1. The value returned by
vender.getSomeCallback is directly used as the value of the callback state
property and the identify based annotation mechanism used in the definition of
the callback will work just fine. meth, because it is expressed using concise
method syntax is processed as a new method definition that is super bound as if
by defineMethod to obj1.
Now consider using extend:
let obj2 = {
callback: vender.getSomeCallback(x,y),
meth() {
super.meth();
this.callback.call(this.target);
};
Object.extend(obj1,obj2);
Object.extend doesn't have any visibility of how the properties of obj2 were
defined. All it sees is two data properties whose values are functions. It if
used Object.defineProperty to process both properties then methwould be super
bound to the wrong object. If it used Object.defineMethod on both properties
then the callback function's identify may change. What Object.extend will have
to do is have a heuristic (if the value is super bound to obj2, then
defineMethod it to obj1. Otherwise, just use defineProperty) that it applies
to function valued data properties. This heuristic should be adequate for
uses that correspond to what could be expressed using .{ but it also allows
other cases where the heuristic may produce something other than the desired
result. Those situations simply don't exist for .{
Use of private names with Object.extend is even more problematic.
Consider something like:
let MixinArrayIterator = (obj) => obj.{
@iterator() {
let coll = this;
return function*() {...yield coll[...}
}
}
which uses the built-in @iterator private name. This works nicely with .{
because the private name is used within the .{ special form and doesn't require
any runtime reflection on the mixin "object". However, to do the same with
Object.extend would requires that extend has reflective visibility of actual
private named properties of obj2. The reflection restrictions on private names
exists to support various high-integrity use cases. In this particular
situation, there is nothing actually "private" in the hight-integrity sense
about @iterator. To make this all work with extend we would probably have to
re-introduce the concept of "unique names" which are like private names but
without the reflection restrictions. That then would introduces additional
complexities.
It is probably possible to support mixin attachment using a functional form
(Object.extend) rather than using a special form (.{} ) but there is a lot more
to it than just a simply syntactic substitutions.
Allen
_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss