Harmony classes [Was: Operator overloading revisited]

Mark S. Miller erights at google.com
Wed Jul 22 12:43:19 PDT 2009


On Wed, Jul 22, 2009 at 11:30 AM, P T Withington<ptw at pobox.com> 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


More information about the es-discuss mailing list