On Jun 5, 2012, at 1:30 PM, Irakli Gozalishvili wrote:
> I just want to (re)express my (and many others) concern about new syntax.
> While Object.extend adds useful feature (Although I think Object.define would
> be more appropriate name) I don't think new syntax is really necessary. I do
> think that new syntax needs a lot more justification then new semantics. I
> also would argue that it's a good idea to alway make syntax changes in a
> separate iteration from the one where associated semantics have being
> introduced. That would allow both community and come tee to see these
> semantics in practice and having more knowledge to decide what syntax sugar
> would work best, if any new syntax even will turn out to be necessary.
>
>> One of these things is installing private named properties upon an existing
>> object. As currently specified, those could not be communicated to an
>> extend function via an object literal because we have disallowed any form of
>> refection upon private named properties. Object.extend could not see them on
>> the literal object in order to copy them. Trying to solve this problem by
>> saying that Object.extend has special reflection privileges would violate
>> the encapsulation that the non-relection on private name properties was
>> intended to provided.
>
> But many other variations of this would do the job as well without a new
> syntax:
>
> Object.extend(target, privates(
> name1, value1,
> name2, value2
> ))
>
I'm not exactly sure what you privates function returns (which is the actual
value that is passed to extend) but it can't be an object where name1 and name
2 are property names because the current rules of private name enumerations
would prevent them from being enumerated. Also I'm assuming that in a typical
case you will want to install a related set of public and private methods on an
object.
I guess you might express this as:
const private1 = new Name;
const private2 = new Name;
const private3 = new Name;
Object.extend(target, {
publicMethod1() {...this[private3]...},
publicMethod2() {...this[private2]()...},
publicDate1: 42,
get publicGet () {return this[private1]}
});
Object.extend(target, privates( //assume private returns a object kind known
to Object.extend that is capable of iterating over the "name" values it was
constructed with
private1, undefined, //private1 need to be a data valued property, not a
method . Let's assume that any non-function value is an indication of that
intent
private2, function(x) {...this[private1]...}, //note that traditional
function declaration must be used. => doen' t have dynamic this and concise
methods are not available here
private3, accessor({get: function() {return
this[private2](this[private1])}}) //accessor produces some sort of
descriptors that identifies the need to add an accessor property
});
more likely you would want to get it all into a single extend call, perhaps by
making the privates be an additional argument or perhaps you intended this
version of extends to support multiple arguments. In either case you would
have
const private1 = new Name;
const private2 = new Name;
const private3 = new Name;
Object.extend(target, {
publicMethod1() {...this[private3]...},
publicMethod2() {...this[private2]()...},
publicDate1: 42,
get publicGet () {return this[private1]}
},
privates( //assume private returns a object of kind known to
Object.extend that is capable of enumerating the "name" values it was
constructed with
private1, undefined, //private1 needs to be a data valued
property, not a method . Let's assume that any non-function value is an
indication of that intent
private2, function(x) {...this[private1]...}, //note that
traditional function declaration must be used. => doen' t have dynamic this and
concise methods are not available here
private3, accessor({get: function() {return
this[private2](this[private1])}}) //accessor produces some sort of descriptor
that identifies the need to add an accessor property
)
);
In either case, once you have to start defining helper functions that generate
argument descriptors like above, I don't see a lot of advantage over using
Object.defineProperty/defineProperties:
const private1 = new Name;
const private2 = new Name;
const private3 = new Name;
Object.defineProperties(target, {
publicMethod1: {value: function() {...this[private3]...}, configurable:
true},
publicMethod2: {value: function() {...this[private2]()...}, configurable:
true}
publicDate1: {value:42, enumerable: true, writable: true, configurable:
true},
publicGet : {get: function () {return this[private1]}, enumerable: true,
writable: true, configurable: true}
};
//private name properties probably can't use defineProperties because of the
private name reflection probation
Object.defineProperty(target, private1, {value:undefined, enumerable: true,
writable: true, configurable: true});
Object.defineProperty(target, private2, {value: function(x)
{...this[private1]...}, configurable: true}) ;
Object.defineProperty(target, private3, {get: function() {return
this[private2](this[private1])}, configurable: true} );
)
);
All of the above look pretty ugly. Just to contrast, here is how the same might
be expressed using mustache:
const private1 = new Name; //private private1, private2, private3; would be
sweeter
const private2 = new Name;
const private3 = new Name;
target.{
publicMethod1() {...this[private3]...},
publicMethod2() {...this[private2]()...},
publicDate1: 42,
get publicGet () {return this[private1]},
@private1: undefined,
@private2(x) {...this[private1]...},
get @private3() {return this[private2](this[private1])}
};
(BTW, I'm using the @pname syntax because I don't believe we are going to get
away without having a way to expression private named property definitions in
object literals and class definitions.)
I guess I don't agree that the non-syntactic form is doing the above just as
well. If the contents of the mustache could be passed as an object literal to
extend then we would be moving in the right direction. However, we would have
to first deal with the private name issues and super rebinding (which I didn't
include in this example)
>>
>> Anther ES6 specific semantic that has always been part of the mustache
>> proposal is the correct binding of methods with super references. I've
>> described this many times. So I'll just describe it again other than to
>> reinforce that mustache is the great way to dynamically associate super
>> referencing method to an object without running into the pitfalls that arise
>> with the defineMethod alternative. I see how with mustache we can live
>> without defineMethld.
>
> But omitting reflection APIs is pretty dangerous path to go with IMO. JS has
> being great as it was always possible to fix things that were not working for
> you. I have feeling that providing semantics only through new syntax may take
> away this great power of JS.
Yes, I agree. One of the principle's I've been trying to follow up to this
point is that there needs to be a procedural way to do any sort of object
construction that can be done syntacticly. But where we are as of the last TC39
meeting is that we don't have either way to add a super bound method to an
already instantiated object. Object.defineMethod was cut and mustache isn't
in. I think mustache is compelling enough that I would probably compromise my
principles and choose it over defineMethod if we only were allow one or the
other. However, I really believe we need a reflective way to do super binding.
Having thought about this a bit since the meeting, I currently think there is
probably a way to have such reflective super binding without creating the
footgun concerns that people had with Object.defineMethod. The way to do it
may be to put the functionality in the reflect module:
reflect.rebindSuper(function, object) //create a new function just like the
first argument but with super bound to object
reflect.hasSuper(function) //test if argument uses a super binding
reflect.isSuperBound(function,object) //test if the function's super binding
is object
I think living there they would be much less of an attractive nuisance and
would provide the necessary capability to do things like enable an
Object.extend like function that would do the right things when encountering
functions that reference super
Allen
>
> Regards
> --
> Irakli Gozalishvili
> Web: http://www.jeditoolkit.com/
>
> On Monday, 2012-06-04 at 09:45 , Brendan Eich wrote:
>
>> Kevin Smith wrote:
>>> Thanks Dave,
>>>
>>> Of the 3 use cases you mentioned, I think unique names are probably
>>> sufficient for 1 and 3. For the second use case (an inaccessible
>>> piece of data associated with an object), would not a weak map also be
>>> appropriate?
>>
>> No, WeakMaps have two problems we've covered in this list:
>>
>> 1. Less efficient than private names.
>>
>> This matters when you can least afford it, and it matters for private
>> names used to program in the large using objects in JS. WeakMaps require
>> special GC handling and they're an extra object with internal mutable
>> state. Private name objects are flat, frozen, and can be optimized a lot
>> harder.
>>
>> 2. You cannot abstract property access:
>>
>> function get(obj, prop) { return obj[prop]; }
>>
>> works with a private name object referenced by prop. No such abstraction
>> can be done with a weak map.
>>
>> /be
>> _______________________________________________
>> es-discuss mailing list
>> [email protected]
>> https://mail.mozilla.org/listinfo/es-discuss
>
> _______________________________________________
> es-discuss mailing list
> [email protected]
> https://mail.mozilla.org/listinfo/es-discuss
_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss