Operator overloading revisited

Mark S. Miller erights at google.com
Mon Jun 29 11:55:44 PDT 2009


On Mon, Jun 29, 2009 at 11:21 AM, Brendan Eich <brendan at mozilla.com> wrote:

> On Jun 28, 2009, at 1:24 PM, Mark S. Miller wrote:
>
> I note that your symmetric suggestion avoids the problem of most other
> symmetric overloading systems, like Cecil, of diffusion of responsibility.
>
>
> "Diffusion" sounds like a problem, a bad thing, but consider (I've quoted
> this before) the use-case:
>
> The generalization of receiver-based dispatch to multiple dispatch provides
> a number of advantages. For example, multimethods support safe covariant
> overriding in the face of subtype polymorphism, providing a natural solution
> to the binary method problem [Bruce et al. 1995; Castagna 1995]. More
> generally, multimethods are useful whenever multiple class hierarchies must
> cooperate to implement a method’s functionality. For example, the code for
> handling an event in an event-based system depends on both which event
> occurs and which component is handling the event.
>


 Let's try a reductio ad absurdum. It seems to be that the argument you're
making applies just as well to

    w.foo(x)

or

   bar(y,z)

In conventional oo reasoning, the first expression is making a request to
the object bound to w. The second is making a request to function bound to
bar. In both cases, the requested object is responsible for deciding what
the next step is in responding to that request. The veracity of the result
is according to the responsible object. If there's a bug in this result, the
responsible object may not itself be the one that is buggy. However, the
blame chain starts there.

What if w doesn't respond to a foo request? Currently our choices are

   1) rewrite our first expression so that it no longer asks w to foo.
   2) modify w or w.[[Prototype]] or something so that w knows how to foo.
       2a) Get the provider/author of w to do this and release a new version
       2b) Fork or rewrite the source for w
       2c) Monkey patch w or w.[[Prototype]] from new module M2
   3) Wrap the original w object with a foo-responding decorator
       3a) Conventional decoration, where other requests are manually
forwarded
       3b) In JS, one can decorate by prototype inheritance
       3c) If we ever have catchalls, one might be able to use them for
decoration

All the options above except for #2c maintain the locality of reponsibility
that makes objects so pleasant to reason about. 2c has come to be regarded
as bad practice. I suggest that one of the main reasons why is that it
destroys this locality. w shouldn't be held responsible if it can't be
responsible. One of the great things about Object.freeze is that w's
provider can prevent 2c on w.

The Cecil-style operator overloading argument, extended to this example,
would enable a fourth option

   4) Allow module M2 to say how w should respond to foo.

I grant that #4 is not as bad as #2c. But does anyone care to argue that #4
would be a good thing in general? If not, why would #4 be ok for operators
but not method or function calls?

-- 
   Cheers,
   --MarkM
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20090629/45c66e95/attachment-0001.html>


More information about the es-discuss mailing list