Operator overloading revisited

Allen Wirfs-Brock Allen.Wirfs-Brock at microsoft.com
Tue Jun 30 10:35:05 PDT 2009


Pulling back from Mark's and Brendan's programming language metaphysics discussion (which I think is interesting and useful) I just wanted to say that I find Christian's proposal quite interesting. It feels like a natural fit to the language as it exists today and doesn't require any new abstraction concepts such as classes, nominal type, value types, etc. although it could be made compatible with any of them. It has a simple conceptual explanation: an operator works with two object if they both associate the same function with that operator. 

It may or may not be the ultimate solution, but I think it deserves serious consideration.

I do have a few thoughts and questions on the proposal as outlined:

I wouldn't want to describe or specify these per object (or per prototype) operator lists as properties.  Too much baggage comes with that concept.  It'd just make them another internal characteristic of objects.  As already mentioned, if you think of them this way there shouldn't be any interactions with Object.freeze or any other existing semantics other than whatever we might choose to explicitly define.

It's too bad that the "this+" and "+this" lists can't be merged but keeping them distinct seems essential to making this scheme work.  However, it also complicates the simple explanation.

I assume that your example really should be defining the operators on prototype objects. Eg:
   Function.defineOperator('+', Point.prototype, Number.prototype, pointPlusNumber);

In order to emphasize the essential difference between "this+" and "+this", I might order the arguments like:
   Function.defineOperator(Point.prototype,'+', Number.prototype, pointPlusNumber);

There seems like there are probably cases where you would only want to define a "this+" or "+this" binding and not both. 

defineOperator probably should be a method on Object and there probably needs to be corresponding introspection methods.  This sort of usability engineering can be worked out if this proposal gains traction.

Allen


>-----Original Message-----
>From: es-discuss-bounces at mozilla.org [mailto:es-discuss-
>bounces at mozilla.org] On Behalf Of Christian Plesner Hansen
>Sent: Sunday, June 28, 2009 7:05 AM
>To: es-discuss at mozilla.org
>Subject: Operator overloading revisited
>
>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.  It uses double dispatch for all
>user-defined operators which makes optimization difficult.  It is
>asymmetrical: the left hand side always controls dispatch.
>
>I'd like to propose an alternative approach that avoids these
>problems.  You could call it "symmetric" operator overloading.  When
>executing the '+' operator in 'a + b' you do the following (ignoring
>inheritance for now):
>
> 1: Look up the property 'this+' in a, call the result 'oa'
> 2: If oa is not a list give an error, no '+' operator
> 3: Look up the property '+this' in b, call the result ob
> 4: If ob is not a list give an error, no '+' operator
> 5: Intersect the lists oa and ob, call the result r
> 6: If r is empty give an error, no '+' operator
> 7: If r has more than one element give an error, ambiguity
> 8: If r[0], call it f, is not a function give an error
> 9: Otherwise, evaluate f(a, b) and return the result.
>
>The way to define a new operator is to add the same function to the
>'this+' list of the left-hand side and the '+this' list on the
>right-hand side.  This would probably be handled best by a simply
>utility function, say Function.defineOperator:
>
>  function pointPlusNumber(a, b) {
>    return new Point(a.x + b, a.y + b);
>  }
>
>  Function.defineOperator('+', Point, Number, pointPlusNumber);
>
>Using this approach it's easy to extend symmetrically:
>
>  function numberPlusPoint(a, b) {
>    return new Point(a + b.x, a + b.y);
>  }
>
>  Function.defineOperator('+', Number, Point, numberPlusPoint);
>
>In this case you need two different functions, one for Point+Number
>and one for Number+Point, but in many cases the same function can be
>used for both:
>
>  function addPoints(a, b) {
>    return new Point(a.x + b.x, a.y + b.y);
>  }
>
>  Function.defineOperator('+', Point, Point, addPoints);
>
>This approach is completely symmetric in the two operands.  Operator
>dispatch is fairly similar to ordinary method dispatch and doesn't
>rely on a type system.  Programmers don't have to manually implement
>double dispatch.  It my be a bit more work to do lookup but on the
>other hand it is straightforward to apply inline caching so often
>you'll only need to do that work once.  It can be extended to deal
>with inheritance -- you might consider all operators up through the
>scope chain and pick the most specific one based on how far up the
>scope chain you had to look.
>
>It may look a bit foreign but I think it has a lot of nice properties.
> Comments?
>
>
>-- Christian
>_______________________________________________
>es-discuss mailing list
>es-discuss at mozilla.org
>https://mail.mozilla.org/listinfo/es-discuss



More information about the es-discuss mailing list