Operator overloading revisited

Maciej Stachowiak mjs at apple.com
Thu Jul 2 02:53:26 PDT 2009


On Jun 28, 2009, at 7:05 AM, 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.  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?

It seems like once you do the defineOperator calls you described  
above, and assuming they work for primitive numbers and not just  
Number objects, then adding two numbers would require two property  
lookups, unless there is an exception for operating on two primitive  
values.

Regards,
Maciej



More information about the es-discuss mailing list