Operator overloading revisited

View: New views
16 Messages — Rating Filter:   Alert me  
< Prev | 1 - 2 - 3 | Next >

RE: Operator overloading revisited

by mikewse :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Brendan Eich wrote:

> If you're worried that the 'class' keyword will hypnotize
> the masses into locking things down overmuch, then you
> don't trust the masses very much. They'll mostly avoid
> new stuff, and any who get burned by inability to monkey-
> patch (which is *not* an unmixed blessing) will retreat,
> and probably start a "don't use 'class'" movement.
>
> This is not 'final' in Java (which pace Mark, I believe
> was overused, including in the standard library, but
> which also has different enough semantics that I wouldn't
> drag it in here as a precedent. We're talking about sugar
> for ES3 and ES5 facilities already implemented, or nearly
> implemented.

Will class inheritance then desugar to classical
prototype/constructor assignments?

Best regards
Mike Wilson

_______________________________________________
es-discuss mailing list
es-discuss@...
https://mail.mozilla.org/listinfo/es-discuss

Parent Message unknown Re: Operator overloading revisited

by Brendan Eich-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Jul 21, 2009, at 6:07 PM, Mike Wilson wrote:

> Brendan Eich wrote:
>> If you're worried that the 'class' keyword will hypnotize
>> the masses into locking things down overmuch, then you
>> don't trust the masses very much. They'll mostly avoid
>> new stuff, and any who get burned by inability to monkey-
>> patch (which is *not* an unmixed blessing) will retreat,
>> and probably start a "don't use 'class'" movement.
>>
>> This is not 'final' in Java (which pace Mark, I believe
>> was overused, including in the standard library, but
>> which also has different enough semantics that I wouldn't
>> drag it in here as a precedent. We're talking about sugar
>> for ES3 and ES5 facilities already implemented, or nearly
>> implemented.
>
> Will class inheritance then desugar to classical
> prototype/constructor assignments?

The current class proposal,

http://wiki.ecmascript.org/doku.php?id=strawman:classes

has zero inheritance.

/be
_______________________________________________
es-discuss mailing list
es-discuss@...
https://mail.mozilla.org/listinfo/es-discuss

RE: Operator overloading revisited

by mikewse :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Brendan Eich wrote:
> On Jul 21, 2009, at 6:07 PM, Mike Wilson wrote:
> > Will class inheritance then desugar to classical
> > prototype/constructor assignments?
>
> The current class proposal,
>
> http://wiki.ecmascript.org/doku.php?id=strawman:classes
>
> has zero inheritance.

Ah right, thanks for the pointer.
Do you expect it to stay this way, and are there good reasons
for not providing inheritance?

Best regards
Mike

_______________________________________________
es-discuss mailing list
es-discuss@...
https://mail.mozilla.org/listinfo/es-discuss

Re: Operator overloading revisited

by Christian Plesner Hansen-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

> The current class proposal,
>
> http://wiki.ecmascript.org/doku.php?id=strawman:classes
>
> has zero inheritance.

I was under the impression that the plan was to develop some form of
inheritance model too.  The strawman says that there is no inheritance
to keep the design simple.  Are you sure you're not throwing the baby
out with the bathwater here?
_______________________________________________
es-discuss mailing list
es-discuss@...
https://mail.mozilla.org/listinfo/es-discuss

Re: Operator overloading revisited

by Alex Russell :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1


On Jul 22, 2009, at 3:10 AM, Christian Plesner Hansen wrote:

>> The current class proposal,
>>
>> http://wiki.ecmascript.org/doku.php?id=strawman:classes
>>
>> has zero inheritance.
>
> I was under the impression that the plan was to develop some form of
> inheritance model too.  The strawman says that there is no inheritance
> to keep the design simple.  Are you sure you're not throwing the baby
> out with the bathwater here?


Lots of babies have already been thrown out in this proposal  
(euphemistically named "Resolved Design Choices"):

   * private by default favors "high integrity" uses of the language,  
punishing the common case and current practice
   * closed-classes ignore both the lessons of Ruby and the way that  
prototypes are currently extended in, say, JQuery
   * the word "prototype" doesn't occur in the proposal anywhere,  
meaning that it's silent on the one existing and useful form of object/
factory-function delegation.

My sense of it is that this proposal is driven by a desire to avoid  
hierarchy-as-composition problems (hositing of methods to high  
positions in hierarchies, etc.) -- which is a well-founded fear.  
However, it avoids it not by adding a composition mechanism like  
traits, but instead seeks to turn classes into factories of objects  
that can't be augmented to fix the errors of initial designs, can't be  
easily composed to form new types, and don't fit well with how current  
JS programmers think about their language.

In short, it helps Harmony classes make all of the same mistakes that  
DOM host objects currently plague developers with.

Regards

- --
Alex Russell
slightlyoff@...
alex@... BE03 E88D EABB 2116 CC49 8259 CF78 E242 59C3 9723

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2 (Darwin)

iD8DBQFKZySoz3jiQlnDlyMRAjpeAJ9R0PkZOTVx7dtV05qzF2X0sisbRACgm3ta
exbKWvCTD1Y8ZkR4BZMQu8U=
=TLUq
-----END PGP SIGNATURE-----
_______________________________________________
es-discuss mailing list
es-discuss@...
https://mail.mozilla.org/listinfo/es-discuss

Re: Operator overloading revisited

by Mark S. Miller-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Wed, Jul 22, 2009 at 3:10 AM, Christian Plesner
Hansen<christian.plesner.hansen@...> wrote:

>> The current class proposal,
>>
>> http://wiki.ecmascript.org/doku.php?id=strawman:classes
>>
>> has zero inheritance.
>
> I was under the impression that the plan was to develop some form of
> inheritance model too.  The strawman says that there is no inheritance
> to keep the design simple.  Are you sure you're not throwing the baby
> out with the bathwater here?

I have been taking the thread starting at
<https://mail.mozilla.org/pipermail/es-discuss/2009-March/009115.html>
together with its references to relevant earlier threads as the
strawman of interest. Several people have encouraged me to update the
wiki. My apologies for not having done so.

The proposal in that latest thread itself does not support
inheritance, which seems consistent with the general sense of the
committee. However, if we do decide to support inheritance, the
earlier thread at
<https://mail.mozilla.org/pipermail/es-discuss/2008-August/006941.html>
shows how to support single inheritance and linearized multiple
inheritance in the same framework.

Alex mentions traits. Traits seem like a more structured form of
behavior sharing than classical inheritance. Lately Alex and I been
reading <http://prog.vub.ac.be/Publications/2009/vub-prog-tr-09-04.pdf>.
Later today I will post some initial thoughts on how this could also
be supported in within the same general framework.

The design of well structured inheritance-like behavior sharing
machinery is far from settled. As with data types, the ideal outcome
would be for ES6 itself to support well all of these as patterns
without building any of them in, so that our users and library authors
can try multiple experiments.

--
    Cheers,
    --MarkM
_______________________________________________
es-discuss mailing list
es-discuss@...
https://mail.mozilla.org/listinfo/es-discuss

Re: Operator overloading revisited

by Brendan Eich-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Jul 22, 2009, at 3:10 AM, Christian Plesner Hansen wrote:

>> The current class proposal,
>>
>> http://wiki.ecmascript.org/doku.php?id=strawman:classes
>>
>> has zero inheritance.
>
> I was under the impression that the plan was to develop some form of
> inheritance model too.  The strawman says that there is no inheritance
> to keep the design simple.  Are you sure you're not throwing the baby
> out with the bathwater here?

Nothing is thrown out by starting simple and then considering our  
options.

We all know many ways (too many!) to support inheritance. Would it  
help to pick a winner prematurely, compared to giving people sugar for  
high-integrity factories, which they must write the long way in ES5,  
or not at all in current JS?

/be
_______________________________________________
es-discuss mailing list
es-discuss@...
https://mail.mozilla.org/listinfo/es-discuss

Harmony classes [Was: Operator overloading revisited]

by P T Withington :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On 2009-07-22, at 14:14EDT, Brendan Eich wrote:

> We all know many ways (too many!) to support inheritance. Would it  
> help to pick a winner prematurely, compared to giving people sugar  
> for high-integrity factories, which they must write the long way in  
> ES5, or not at all in current JS?


On 2009-07-22, at 10:39EDT, Alex Russell wrote:

> In short, it helps Harmony classes make all of the same mistakes  
> that DOM host objects currently plague developers with.

So, depending on your point of view, Harmony classes allow the user to  
create objects that have both the same integrity, and the same  
limitations, as native objects.

I suppose that's a start.  But if they don't even support prototypical  
inheritance, I'll never be able to use them.  Give them prototypical  
inheritance, and I will probably adopt them for their integrity, using  
my existing pre-processor to emulate the classes and mixins I really  
want.

My only quibble is whether it is confusing to name something so  
limited 'class'?

On 2009-07-22, at 10:52EDT, Mark S. Miller wrote:

> Lately Alex and I been
> reading <http://prog.vub.ac.be/Publications/2009/vub-prog- 
> tr-09-04.pdf>.
> Later today I will post some initial thoughts on how this could also
> be supported in within the same general framework.

Thanks for this pointer.  I am just starting to read and it looks  
intriguing.  Traits that also have state might just make me give up my  
mixins!
_______________________________________________
es-discuss mailing list
es-discuss@...
https://mail.mozilla.org/listinfo/es-discuss

Re: Harmony classes [Was: Operator overloading revisited]

by Mark S. Miller-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Wed, Jul 22, 2009 at 11:30 AM, P T Withington<ptw@...> wrote:

> On 2009-07-22, at 10:52EDT, Mark S. Miller wrote:
>
>> Lately Alex and I been
>> reading <http://prog.vub.ac.be/Publications/2009/vub-prog-tr-09-04.pdf>.
>> Later today I will post some initial thoughts on how this could also
>> be supported in within the same general framework.
>
> Thanks for this pointer.  I am just starting to read and it looks
> intriguing.  Traits that also have state might just make me give up my
> mixins!


Given the following helper abstractions:

------------------------
const traitConflict() {
  throw new Error("trait conflict");
}

const conflictDesc = Object.freeze({
  get: traitConflict,
  set: undefined,
  enumerable: false,
  configurable: true
});

const isSameDesc(desc1, desc2) { ... }

const addTrait(self, trait, opt_advice) {
  const advice = opt_advice || {};
  Object.getOwnPropertyNames(trait).forEach(const(k) {
    const newDesc = Object.getOwnPropertyDescriptor(trait, k);
    if (k in advice) {
      const k2 = advice[k];
      if (k2) { k = k2; /*String(k2); ? */ } else { return; }
    }
    const oldDesc = Object.getOwnPropertyDescriptor(self, k);
    if (oldDesc) {
      if (isSameDesc(oldDesc, newDesc)) {
        // already cool
      } else {
        Object.defineProperty(self, k, conflictDesc);
      }
    } else {
      Object.defineProperty(self, k, newDesc);
    }
  });
}
------------------------

and using no sugar beyond that defined in the thread starting at
<https://mail.mozilla.org/pipermail/es-discuss/2009-March/009115.html>,
here is the main example from Tom's paper:

------------------------
class AnimationTrait(self, refreshRate) {
  const timer = makeTimer();
  public start() {
    timer.everyDo(refreshRate, const() { self.animate(); });
  }
  public stop() { timer.reset(); }
}

const ParticleTrait(self, radius, moveRate, dx, dy) {
  const resultTrait = {};
  addTrait(resultTrait, CircleTrait(self, radius));
  addTrait(resultTrait, AnimationTrait(self, moveRate), {
    start: 'startMoving',
    stop: false
  });
  addTrait(resultTrait, object {
    public animate() { self.move(dx, dy); }
  });
  return Object.freeze(resultTrait);
}
const ParticleMorph(radius, moveRate, dx, dy) {
  var self = {};
  addTrait(self, ParticleTrait(self, radius, moveRate, dx, dy));
  return Object.freeze(self);
}
------------------------

Once we know whether or not we want to adopt traits, and whether we
wish to adopt precisely Tom's traits semantics, we could consider
further sugar for supporting exactly this pattern. Until then, and in
order to get to such a state of clarity, it is pleasing that traits
semantics such as Tom's can be expressed well directly in terms of the
currently proposed non-inheriting classes-as-sugar system.


--
    Cheers,
    --MarkM
_______________________________________________
es-discuss mailing list
es-discuss@...
https://mail.mozilla.org/listinfo/es-discuss

Re: Harmony classes [Was: Operator overloading revisited]

by Mark Miller-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

> const ParticleMorph(radius, moveRate, dx, dy) {
>  var self = {};
>  addTrait(self, ParticleTrait(self, radius, moveRate, dx, dy));
>  return Object.freeze(self);
> }

Given the additional helper

const complete(MakeTrait) {
  return const MakeObject(...rest) {
    var self = {};
    addTrait(self, MakeTrait(self, ...rest));
    return Object.freeze(self);
  }
}

we can define ParticleMorph as simply

const ParticleMorph = complete(ParticleTrait);



--
Text by me above is hereby placed in the public domain

    Cheers,
    --MarkM
_______________________________________________
es-discuss mailing list
es-discuss@...
https://mail.mozilla.org/listinfo/es-discuss

RE: Operator overloading revisited

by mikewse :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

[Still staying in this thread although bad match to subject line, as
I'd like to continue on the discussion of open vs closed classes]

Brendan Eich wrote:

>
> On Jul 22, 2009, at 3:10 AM, Christian Plesner Hansen wrote:
>
> >> The current class proposal,
> >>
> >> http://wiki.ecmascript.org/doku.php?id=strawman:classes
> >>
> >> has zero inheritance.
> >
> > I was under the impression that the plan was to develop some form of
> > inheritance model too.  The strawman says that there is no
> inheritance
> > to keep the design simple.  Are you sure you're not
> throwing the baby
> > out with the bathwater here?
>
> Nothing is thrown out by starting simple and then considering our  
> options.

I agree a lot with Alex about wanting the ability to create non-
frozen classes with the new class mechanism (with respect for
not having the whole picture as you in the committee have).

Once the new class mechanism was deployed I was hoping to be able
to use it for any class-oriented problem, and not having to fall
back on old-style prototypes/constructors for certain kinds of
classes.

With the current (small) feature list of classes I guess it's hard
to provide any hard arguments against keeping old-style
constructors for open classes, and it *is* elegant to keep the
purpose of existing language mechanisms.
Though, to me it looks like there is a risk that this design will
not fit so well when later expanding the feature list with f ex
inheritance or class introspection, and that will leave open
classes in the back-water and developers facing questions like:
- Ah, you want to use the new non-clunky inheritance mechanism
  that doesn't force you to actually set up the inheritance through
  a constructor call to the superclass?
  Sorry, only available in frozen classes.
- Or, you want the new inheritance mechanism that chains constructor
  calls at instance creation? Only available in frozen classes.
- Or, you want to introspect the class to see what members instances
  will get, without creating and introspecting an actual instance?
  Only in frozen classes.

Of course I am only speculating about potential future additions
here, but it is easy to fear that the old-style constructors will
have a hard time keeping up with a class mechanism that actually
has a class declaration to build features upon.

Best regards
Mike

_______________________________________________
es-discuss mailing list
es-discuss@...
https://mail.mozilla.org/listinfo/es-discuss

Re: Harmony classes [Was: Operator overloading revisited]

by Tom Van Cutsem :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

> On Wed, Jul 22, 2009 at 11:30 AM, P T Withington<ptw@...> wrote:
>> On 2009-07-22, at 10:52EDT, Mark S. Miller wrote:
>>
>>> Lately Alex and I been
>>> reading <http://prog.vub.ac.be/Publications/2009/vub-prog-tr-09-04.pdf 
>>> >.
>>> Later today I will post some initial thoughts on how this could also
>>> be supported in within the same general framework.
>>
>> Thanks for this pointer.  I am just starting to read and it looks
>> intriguing.  Traits that also have state might just make me give up  
>> my
>> mixins!

I'm very pleased to see that our work is relevant for the Javascript  
community. If it's any help, the slides I used to present the paper a  
couple of weeks ago at ECOOP09 are available at: http://prog.vub.ac.be/~tvcutsem/presentations/Traits-ECOOP09.pdf

Some comments on Mark's proposal follow:

> Given the following helper abstractions:
>
> ------------------------
> const traitConflict() {
>  throw new Error("trait conflict");
> }
>
> const conflictDesc = Object.freeze({
>  get: traitConflict,
>  set: undefined,
>  enumerable: false,
>  configurable: true
> });

Do I get it right that a trait composition conflict is only raised  
upon accessing the conflicting property? In AmbientTalk, the error is  
signaled at composition-time (i.e. as if your addTrait method would  
raise an exception). What's your rationale for deferring the exception  
until the property is accessed?

> const isSameDesc(desc1, desc2) { ... }
>
> const addTrait(self, trait, opt_advice) {
>  const advice = opt_advice || {};
>  Object.getOwnPropertyNames(trait).forEach(const(k) {
>    const newDesc = Object.getOwnPropertyDescriptor(trait, k);
>    if (k in advice) {
>      const k2 = advice[k];
>      if (k2) { k = k2; /*String(k2); ? */ } else { return; }
>    }
>    const oldDesc = Object.getOwnPropertyDescriptor(self, k);
>    if (oldDesc) {
>      if (isSameDesc(oldDesc, newDesc)) {
> // already cool
>      } else {
> Object.defineProperty(self, k, conflictDesc);
>      }
>    } else {
>      Object.defineProperty(self, k, newDesc);
>    }
>  });
> }
> ------------------------

If I understand correctly, the line

        Object.defineProperty(self, k, newDesc);

installs the trait's 'newDesc' property in the object denoted by  
'self'. Two issues need be taken into account if the property refers  
to a method:

- the trait method needs a way to refer to the composite, such that it  
can invoke required methods. From your example below I infer that  
'self' can be made to refer to the composite because you explicitly  
parameterize classes with 'self'. This makes sense, especially for  
traits which can be seen as 'incomplete classes'.

- if the trait method refers to lexically free identifiers, will these  
identifiers be bound correctly if the method is invoked on the  
composite object? More concretely, using the example below: if the  
method 'start' is invoked on a ParticleMorph, can I rest assured that  
the reference to 'timer' in AnimationTrait's 'start' method refers to  
AnimationTrait's timer?

I think it works because you represent methods simply as functions  
(closures). I assume that newDesc's 'get' propety refers to a function  
that represents the trait method, and this function has closed over  
its lexical scope and will correctly refer to lexically free  
identifiers even when installed in a different object. Am I right? If  
this is the case, that's great because it avoids the need for Self-
style delegation, which we required in our paper because methods were  
not mere functions (they were implicitly parameterized with 'self',  
and delegation was required to late-bind 'self' to the composite).

> and using no sugar beyond that defined in the thread starting at
> <https://mail.mozilla.org/pipermail/es-discuss/2009-March/ 
> 009115.html>,
> here is the main example from Tom's paper:
>
> ------------------------
> class AnimationTrait(self, refreshRate) {
>  const timer = makeTimer();
>  public start() {
>    timer.everyDo(refreshRate, const() { self.animate(); });
>  }
>  public stop() { timer.reset(); }
> }
>
> const ParticleTrait(self, radius, moveRate, dx, dy) {
>  const resultTrait = {};
>  addTrait(resultTrait, CircleTrait(self, radius));
>  addTrait(resultTrait, AnimationTrait(self, moveRate), {
>    start: 'startMoving',
>    stop: false
>  });
>  addTrait(resultTrait, object {
>    public animate() { self.move(dx, dy); }
>  });
>  return Object.freeze(resultTrait);
> }
> const ParticleMorph(radius, moveRate, dx, dy) {
>  var self = {};
>  addTrait(self, ParticleTrait(self, radius, moveRate, dx, dy));
>  return Object.freeze(self);
> }
> ------------------------
>
> Once we know whether or not we want to adopt traits, and whether we
> wish to adopt precisely Tom's traits semantics, we could consider
> further sugar for supporting exactly this pattern. Until then, and in
> order to get to such a state of clarity, it is pleasing that traits
> semantics such as Tom's can be expressed well directly in terms of the
> currently proposed non-inheriting classes-as-sugar system.
>
>
> --
>    Cheers,
>    --MarkM

_______________________________________________
es-discuss mailing list
es-discuss@...
https://mail.mozilla.org/listinfo/es-discuss

Re: Harmony classes [Was: Operator overloading revisited]

by Mark S. Miller-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Fri, Jul 24, 2009 at 1:08 AM, Tom Van Cutsem<tvcutsem@...> wrote:

>>> On 2009-07-22, at 10:52EDT, Mark S. Miller wrote:
>> Given the following helper abstractions:
>>
>> ------------------------
>> const traitConflict() {
>>  throw new Error("trait conflict");
>> }
>>
>> const conflictDesc = Object.freeze({
>>  get: traitConflict,
>>  set: undefined,
>>  enumerable: false,
>>  configurable: true
>> });
>
> Do I get it right that a trait composition conflict is only raised upon
> accessing the conflicting property? In AmbientTalk, the error is signaled at
> composition-time (i.e. as if your addTrait method would raise an exception).
> What's your rationale for deferring the exception until the property is
> accessed?

This change of semantics was more exploratory than purposeful. A
retroactive rationalization though is that a conflict that isn't used
shouldn't need resolution. C++ does something like this for its
multiple inheritance. Of course, they detect possible use statically
as well, so they don't pay the price of delaying the failure till the
use actually occurs.

If desired, it would be simple to alter the scheme I posted so that it
signals the conflict at composition time instead. I have no strong
opinion on which we should prefer.


>> const isSameDesc(desc1, desc2) { ... }
>>
>> const addTrait(self, trait, opt_advice) {
>>  const advice = opt_advice || {};
>>  Object.getOwnPropertyNames(trait).forEach(const(k) {
>>   const newDesc = Object.getOwnPropertyDescriptor(trait, k);
>>   if (k in advice) {
>>     const k2 = advice[k];
>>     if (k2) { k = k2; /*String(k2); ? */ } else { return; }
>>   }
>>   const oldDesc = Object.getOwnPropertyDescriptor(self, k);
>>   if (oldDesc) {
>>     if (isSameDesc(oldDesc, newDesc)) {
>>        // already cool
>>     } else {
>>        Object.defineProperty(self, k, conflictDesc);
>>     }
>>   } else {
>>     Object.defineProperty(self, k, newDesc);
>>   }
>>  });
>> }
>> ------------------------
>
> If I understand correctly, the line
>
>        Object.defineProperty(self, k, newDesc);
>
> installs the trait's 'newDesc' property in the object denoted by 'self'.

Yes.

> Two
> issues need be taken into account if the property refers to a method:
>
> - the trait method needs a way to refer to the composite, such that it can
> invoke required methods. From your example below I infer that 'self' can be
> made to refer to the composite because you explicitly parameterize classes
> with 'self'.

Yes. That's the purpose of the 'self' parameter in that code.

> This makes sense, especially for traits which can be seen as
> 'incomplete classes'.
>
> - if the trait method refers to lexically free identifiers, will these
> identifiers be bound correctly if the method is invoked on the composite
> object? More concretely, using the example below: if the method 'start' is
> invoked on a ParticleMorph, can I rest assured that the reference to 'timer'
> in AnimationTrait's 'start' method refers to AnimationTrait's timer?

Yes.

> I think it works because you represent methods simply as functions
> (closures). I assume that newDesc's 'get' prope[r]ty refers to a function that
> represents the trait method, and this function has closed over its lexical
> scope and will correctly refer to lexically free identifiers even when
> installed in a different object. Am I right?

Yes, except for one detail. In this case, it is newDesc's 'value'
property rather than its get property. Starting with ES5, a property
is either a "data property" or an "accessor property". The descriptor
of a data property has the form
    { value: <any>, writable: <boolean>, enumerable: <boolean>,
configurable: <boolean> }
The descriptor of an accessor property has the form
    { get: <function () -> any>, set: <function (any)>, enumerable:
<boolean>, configurable: <boolean> }

Reading a data property is equivalent to reading the value of the
'value' property of a descriptor of the data property's current state.
Reading an accessor property is equivalent to calling the value of the
'get' property of a descriptor of the accessor property's current
state. The start method in the example is a data property, so its
descriptor would be of the first form.

I used an accessor property in my original post only to represent a
conflicted property, so the complaint would happen on any attempt to
read the property, whether or not the read was followed by a call.

> If this is the case, that's
> great because it avoids the need for Self-style delegation, which we
> required in our paper because methods were not mere functions (they were
> implicitly parameterized with 'self', and delegation was required to
> late-bind 'self' to the composite).

Yes, exactly. In this pattern, as in your paper, lexical variables are
not affected by trait composition. For a property 'foo' exported by a
trait, within that trait definition it can be referred to either by
lexical variable 'foo' or as 'self.foo'. In the first case, it refers
to the 'foo' locally defined by that trait itself. In the second, it
refers to whatever 'foo' is finally bound to on the self object
resulting from the composition of traits.


>> ------------------------
>> class AnimationTrait(self, refreshRate) {
>>  const timer = makeTimer();
>>  public start() {
>>   timer.everyDo(refreshRate, const() { self.animate(); });
>>  }
>>  public stop() { timer.reset(); }
>> }
>>
>> const ParticleTrait(self, radius, moveRate, dx, dy) {
>>  const resultTrait = {};
>>  addTrait(resultTrait, CircleTrait(self, radius));
>>  addTrait(resultTrait, AnimationTrait(self, moveRate), {
>>   start: 'startMoving',
>>   stop: false
>>  });
>>  addTrait(resultTrait, object {
>>   public animate() { self.move(dx, dy); }
>>  });
>>  return Object.freeze(resultTrait);
>> }
>> const ParticleMorph(radius, moveRate, dx, dy) {
>>  var self = {};
>>  addTrait(self, ParticleTrait(self, radius, moveRate, dx, dy));
>>  return Object.freeze(self);
>> }
>> ------------------------




--
    Cheers,
    --MarkM
_______________________________________________
es-discuss mailing list
es-discuss@...
https://mail.mozilla.org/listinfo/es-discuss

Re: Harmony classes [Was: Operator overloading revisited]

by Tom Van Cutsem :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

>> Do I get it right that a trait composition conflict is only raised  
>> upon
>> accessing the conflicting property? In AmbientTalk, the error is  
>> signaled at
>> composition-time (i.e. as if your addTrait method would raise an  
>> exception).
>> What's your rationale for deferring the exception until the  
>> property is
>> accessed?
>
> This change of semantics was more exploratory than purposeful. A
> retroactive rationalization though is that a conflict that isn't used
> shouldn't need resolution. C++ does something like this for its
> multiple inheritance. Of course, they detect possible use statically
> as well, so they don't pay the price of delaying the failure till the
> use actually occurs.
>
> If desired, it would be simple to alter the scheme I posted so that it
> signals the conflict at composition time instead. I have no strong
> opinion on which we should prefer.

Me neither, as long as it's obvious to the programmer what composition  
caused the conflict.

>>> const isSameDesc(desc1, desc2) { ... }
>>>
>>> const addTrait(self, trait, opt_advice) {
>>>  const advice = opt_advice || {};
>>>  Object.getOwnPropertyNames(trait).forEach(const(k) {
>>>   const newDesc = Object.getOwnPropertyDescriptor(trait, k);
>>>   if (k in advice) {
>>>     const k2 = advice[k];
>>>     if (k2) { k = k2; /*String(k2); ? */ } else { return; }
>>>   }
>>>   const oldDesc = Object.getOwnPropertyDescriptor(self, k);
>>>   if (oldDesc) {
>>>     if (isSameDesc(oldDesc, newDesc)) {
>>>        // already cool
>>>     } else {
>>>        Object.defineProperty(self, k, conflictDesc);
>>>     }
>>>   } else {
>>>     Object.defineProperty(self, k, newDesc);
>>>   }
>>>  });
>>> }
>>> ------------------------

It's really nice that you can specify trait composition in Javascript  
using metaprogramming this easily. I checked your implementation  
against our implementation of traits in AmbientTalk. There is one  
issue that we had to work around, which relates to "default  
properties" that are present in every object: we had to exclude such  
properties 'by default' since they would otherwise always cause  
conflicts. My guess is that if such properties exist in JS, you would  
probably set their 'enumerable' field to false to filter them out.

>> I think it works because you represent methods simply as functions
>> (closures). I assume that newDesc's 'get' prope[r]ty refers to a  
>> function that
>> represents the trait method, and this function has closed over its  
>> lexical
>> scope and will correctly refer to lexically free identifiers even  
>> when
>> installed in a different object. Am I right?
>
> Yes, except for one detail. In this case, it is newDesc's 'value'
> property rather than its get property. Starting with ES5, a property
> is either a "data property" or an "accessor property". The descriptor
> of a data property has the form
>    { value: <any>, writable: <boolean>, enumerable: <boolean>,
> configurable: <boolean> }
> The descriptor of an accessor property has the form
>    { get: <function () -> any>, set: <function (any)>, enumerable:
> <boolean>, configurable: <boolean> }

Thanks for the clarification. Could you point me to a page that  
explains the rationale behind distinguishing data properties from  
accessor properties? At first sight, it appears you don't need both  
since accessor properties can easily subsume data properties.

Kind regards,
Tom
_______________________________________________
es-discuss mailing list
es-discuss@...
https://mail.mozilla.org/listinfo/es-discuss

Re: Harmony classes [Was: Operator overloading revisited]

by Brendan Eich-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Jul 27, 2009, at 2:56 AM, Tom Van Cutsem wrote:

 Could you point me to a page that explains the rationale behind distinguishing data properties from accessor properties? At first sight, it appears you don't need both since accessor properties can easily subsume data properties.

ES5 is a draft standard based on de-facto standards in JavaScript implementations. Accessor properties, commonly called "getters and setters", originated almost ten years ago in Mozilla's SpiderMonkey JS engine. They were reverse-engineered into other engines more recently.

JS, originally in Netscape 2 in 1995, and in ECMA-262 editions 1 through 3 (the last edition before ES5, finalized in 1999), had only data properties, with class-wise [[Get]] and [[Put]] meta-methods in the spec but not exposed to programmers.

My inspirations for JS back in 1995 included Scheme and Self, neither of which subsumes anything like data properties under accessor properties. What's more, I didn't have time in the early days to support user-defined accessors, although native ones existed under the hood in custom objects defined by the implementation (i.e., "the DOM"). Thus the ES1-3 standards do not describe properties as pairs of accessor functions, or talk about exposing such functions to programmers and allowing custom getters and setters to be defined.

Since accessors came later, they are observable. You can tell they're there using the ES5 meta-programming APIs. They differ from data properties in other ways; e.g., you can't shadow an accessor property in a prototype object by assignment. Thus ES5 can't easily or profitably recast all properties as accessor properties. There would still be "data properties" even if the spec formalized on top of accessors.

/be

_______________________________________________
es-discuss mailing list
es-discuss@...
https://mail.mozilla.org/listinfo/es-discuss

Re: Harmony classes [Was: Operator overloading revisited]

by Mark S. Miller-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Mon, Jul 27, 2009 at 2:56 AM, Tom Van Cutsem<tvcutsem@...> wrote:

>>>> const isSameDesc(desc1, desc2) { ... }
>>>>
>>>> const addTrait(self, trait, opt_advice) {
>>>>  [...]
>>>>  if (oldDesc) {
>>>>    if (isSameDesc(oldDesc, newDesc)) {
>>>>       // already cool
>>>>    } else {
>>>>       Object.defineProperty(self, k, conflictDesc);
>>>>    }
>>>>  } else {
>>>>    Object.defineProperty(self, k, newDesc);
>>>>  }
>>>>  });
>>>> }
>>>> ------------------------
>
> It's really nice that you can specify trait composition in Javascript using
> metaprogramming this easily. I checked your implementation against our
> implementation of traits in AmbientTalk. There is one issue that we had to
> work around, which relates to "default properties" that are present in every
> object: we had to exclude such properties 'by default' since they would
> otherwise always cause conflicts.

That's why I put the isSameDesc() call into the conditional above. If
the same name is bound to the same descriptions into two different
traits being composed -- as would happen for example in a diamond
composition pattern -- then there's no conflict.


> My guess is that if such properties exist
> in JS, you would probably set their 'enumerable' field to false to filter
> them out.

The equivalent of default properties in JS are properties defined on
Object.prototype. Until ES5, all object necessarily inherited from
Object.prototype, and typically will still. The properties defined by
the spec on Object.prototype are indeed defined as non-enumerable. And
in ES5, new properties that anyone defines on Object.prototype can
(and therefore should) be defined as non-enumerable as well.

But none of that is why we avoid a conflict for such methods. Since
addTrait() enumerates properties with Object.getOwnPropertyNames(),
this enumerates all own properties whether enumerable or not. An "own"
property is a property defined directly on the object, as opposed to
an "inherited" property. So we avoid the defaults from
Object.prototype but we do compose non-enumerable properties. We dodge
the false-conflict problem with the isSameDesc() check explained
above.

--
    Cheers,
    --MarkM
_______________________________________________
es-discuss mailing list
es-discuss@...
https://mail.mozilla.org/listinfo/es-discuss
< Prev | 1 - 2 - 3 | Next >