« Return to Thread: Operator overloading revisited

Re: Operator overloading revisited

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

Reply to Author | View in Thread

On Sun, Jun 28, 2009 at 7:05 AM, Christian Plesner Hansen <christian.plesner.hansen@...> wrote:
Following the decimal discussion where values came up I looked for
information on that.  The most substantial I could find was Mark's
operator overloading strawman.

I think the current strawman has a number of weaknesses.  It relies on
the (hypothetical) type system which makes it fundamentally different
from normal method dispatch.


Are you referring to <https://mail.mozilla.org/pipermail/es-discuss/2009-January/008535.html>? It starts with:

Define a new nominal type named, let's say, "Operable". (I'm not stuck on
this name. Perhaps "Numeric"?) We don't yet know what nominal type system
Harmony will have, so for concreteness, and to separate issues, let's use
"instanceof" as our nominal type test, where only functions whose
[...suggested restrictions on when this test applies, but all without presuming any "type"s beyond what ES5 already supports...]

I'm glad you started with one of the motivating problem cases: "+". The reason I conditioned the new overloadings on Operable is to handle the "+" case, which, to be upwards compatible, must continue to .toString() on legacy non-number objects. One of Sam's earlier decimal proposals ran aground on this "+" problem. IIUC, your proposal could deal with the legacy "+" problem by duck typing on "this+" and "+this"? This may be adequate.

My strawman was written without any concept of value types at the time. In committee, Waldemar then raised the "===" issue. "===" currently has the great virtues that it is a reliable equality test that does not run user code during the comparison, and whose veracity does not depend on user code. NaN and -0 aside, if x === y, then they are observably indistinguishable. Any occurrence of that value of x in a computation state can be substituted for any occurrence of that value of y in that computation state without effecting the semantics of that state. We did not want to lose those virtues, so we do not want to allow user defined abstractions to overload ===. Neither do we want

    Point(3, 5) === Point(3, 5)

to be false. AFAIK, the only way to reconcile these goals is to introduce value types. In earlier internal email I summarized the value-type thinking as:

* start with something like my operator-overloading-by-double-dispatch
  proposal,
* but tie the ability to respond to operators to being a value -- an
  instance of a value type/class.
* A value is necessarily frozen and compares "===" based on
  cycle-tolerant pairwise "===" comparison of named properties
  [missing from earlier email: as well as [[Prototype]] and [[Class]] properties].
* Therefore, a value is indistinguishable from a shallow copy of the
  same value. Strings are a precedent.
* Values would be able to overload "==" but not "===".
* "===" would remain reliable and not cause user code to run during
  the comparison.


It seems to me that the Operable-test and value-type issues are orthogonal to the core suggestion of your email: whether operator dispatch is based on Smalltalk-like double dispatch, in which the left side is asymmetrically in charge, or on mutual agreement which is indeed symmetric. The first bullet could be changed to your proposal without affecting the rest of the value-type issue.

I note that your symmetric suggestion avoids the problem of most other symmetric overloading systems, like Cecil, of diffusion of responsibility. Since your's only proceeds under mutual agreement, both operands are responsible for the result. Unfortunately, this means that new libraries like Point, in order to allow "pt + number" or "number + pt", must in practice monkey patch Number.prototype to know about these new overloads. Should Number.prototype in that frame (global object context) already be frozen to prevent such monkey patching, then this Point extension can no longer be loaded into that frame.

By comparison, the cool thing about double dispatch is that new types can arrange to work with old types without monkey patching, given only that the old types engage in the generic enabling default behavior and that the new types have explicit cases for the old types it knows about and wishes to work with. Might there be a way to combine the modular extension virtues of double-dispatch with the symmetric-responsibility virtues of your proposal? I don't know. But if so, that would be awesome!

--
   Cheers,
   --MarkM

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

 « Return to Thread: Operator overloading revisited