<| with function RHS is brittle

Herby Vojčík herby at mailbox.sk
Mon Mar 5 02:33:20 PST 2012


Hello,

I now realized that I had a mistake in my mental model and that the 
difference is smaller than I thought. Whatever LHS is, it always behaves 
the same: it is set as a {[Prototype]] of the RHS. Putting LHS.prototype 
into RHS.prototype is pure "addon". Seeing it this way, it is ok.

I was in the impression, that the behaviour differs in principle, and 
that different object are put in RHS.[[Prototype]]. I don't know why I 
thought that.

Maybe to clear that confusion, should it happen with others, it should 
be formulated in some way that dispels it.

Sorry for the false alarm,

Herby

Allen Wirfs-Brock wrote:
>
> On Mar 4, 2012, at 1:59 PM, Herby Vojčík wrote:
>
>> Hello,
>>
>> I feel uneasy about this in <| proposal:
>>
>>> If the LHS operand has a property named prototype and the RHS
>>> operand is a function expression then the [[Prototype]] of the
>>> function object is set to the LHS object and the prototype property
>>> of the new function is set to a new object whose [[Prototype]] is the
>>> value of the LHS’s prototype property.
>>
>> It looks a little "perlish" to me, in the sense that when you write
>>
>> x <| function (...) {...}
>>
>> you must guard what x is because you can get two different outcomes
>> (same as perl can use element in place of container, which backfires if
>> the element itself is a container). I think it should be rephrased as:
>>
>>> If the RHS operand is a function expression then
>>> a. if the LHS operand has a property named prototype the
>>> [[Prototype]] of the function object is set to the LHS object and the
>>> prototype property of the new function is set to a new object whose
>>> [[Prototype]] is the value of the LHS’s prototype property.
>>> b. otherwise TypeError exception is thrown.
>>
>> Herby
>
> Here[1] is a specific instance of how this feature is useful:
>
> //define a non constructible superclass that provides some
> Smalltalk-like conventions
> const AbstractClass = Function.prototype <| {
> subclassResponsibility() {throw new Error(this.name+" did not
> implemented an abstract method")},
> shouldNotImplement() {throw new Error(this.name+" should not implemented
> by "+this.name)},
> name: "AbstractClass",
> prototype: Object.prototype <|{
> get class() {return this.constructor},
> error(message) {throw new Error(message)},
> subclassResponsibility() {return this.class.subclassResponsibility()},
> shouldNotImplement() {return this.class.shouldNotImplement()},
> errorSubscriptBounds(index) {this.error("subscript is out of bounds:
> "+index)}
> }
> };
>
>
> See the full js file for its use in context. But the basic idea is that
> we need to set up the root of both the class-side and instance-side
> inheritance chains. Your definition would make that impossible. This is
> an unusual use-case but it does occur when working at the root
> inheritance level. In addition to this specific example I think it will
> be useful when languages that are compile to JS need to implement their
> language-specific inheritance hierarchies while still exploiting the
> mechanism provided by JS.
>
> I do want to intend to put some further though into the details of how
> I've specified this, but I think it is a capability that we need.
>
> Allen
>
> [1]:
> https://github.com/allenwb/ESnext-experiments/blob/master/ST80collections-exp1.js#L90


More information about the es-discuss mailing list