Operator overloading revisited
Brendan Eich
brendan at mozilla.com
Fri Jul 3 04:20:24 PDT 2009
On Jul 3, 2009, at 1:21 AM, Christian Plesner Hansen wrote:
>> Likewise, for user-defined function foo, foo.prototype is writable
>> -- but
>> not so for built-in constructor functions, and not so for classes
>> as sugar
>> (more below).
>
> All JS code currently in existence is based on user-defined functions.
> For me that is the only case worth considering. That might explain
> the differences in our views.
That's doesn't square with your proposal:
function pointPlusNumber(a, b) {
return new Point(a.x + b, a.y + b);
}
Function.defineOperator('+', Point, Number, pointPlusNumber);
If you want to amend per Allen's suggestion by imposing fruitless,
verbose ".prototype" taxes on the last line, so it reads
Function.defineOperator('+', Point.prototype, Number.prototype,
pointPlusNumber);
(or with some other argument order), then what good have you done for
users? Unless Point and Number are frozen or otherwise configured in a
non-default way, the next line could change one or both .prototype
values and make later instances miss the operator.
Sure, that would be a case of "Doctor, it hurts when I do this" (so
don't do it), but the same argument applies to instanceof, yet one
writes (p instanceof Point), not (p instanceof Point.prototype).
You can't have it both ways. Either mutable .prototype (or mutable
function binding, e.g. Point in the global object, or whatever scope
it's bound in) is a problem that requires freezing or equivalent lock-
down, or it isn't. In any event, there's no reason to impose
the .prototype tax, and instanceof-consistency (evolutionary :-P)
reason not to.
> I'm not a language revolutionary, I prefer gradual evolution.
Your political rhetoric is off target. Classes as sugar are not
revolutionary, they build on evolutionary ES3 closures and ES5
Object.freeze and similar features by adding syntactic sugar. They are
mostly about "best practices" and "best usability" design defaults for
higher-integrity factories than functions called via new can ever be
by themselves (due to compatibility).
> If you have the option to use a model that works with the existing
> language and that integrates well even (that's subjective of course)
> why would you limit it to classes or values?
Because we're talking about value types, with that (typeof a == typeof
b && a == b) <=> a === b implication extensible to user-defined value
types, along with numeric literal syntax.
Value types are new "UI". The benefits won't accrue to user-defined
functions as constructors without more opt-in API. And value types
deserve first-class syntax, just as classes as sugar do. C# has
structs, as Sam pointed out.
Without picking the exact syntax right now, the point remains that we
have not been proposing only operators, or even only operators for
user-defined constructor functions. We're talking about user-defined
value types, ideally with concise, convenient defining as well as
invoking syntax.
> The reliance of these
> new features on each other will just lead them to become a
> language-within-a-language, rather than an evolution of the existing
> language.
There are lots of subsets in the language already, this is a teaching
and user preference outcome that we can't and shouldn't stop. Multiple
paradigms and well-ordered subsets are not a problem, they are a
success condition.
But adding operators without considering first-class value types (==/
=== and literal syntax) looks like a mistake.
>> You could, but your proposal nicely avoided noisy ".prototype"
>> expressions
>> all over, as Allen suggested in reply.
>
> That was a typo.
Why require .prototype noise when instanceof does not? Talk about
evolution vs. revolution doesn't justify this break from instanceof's
reliance on users to keep their constructor.prototype values intact --
or not, as they please.
> If people can live with defining their methods as
>
> Foo.prototype.bar = function () { ... }
That's not the l33t way, of course:
Foo.prototype = {
bar: function () {...}
...
};
But this is noisy and error-prone still, and you are wrong that what
one "can live with" should be the last word. People "live with" all
sorts of problems in the world, including in JS as it is, and
certainly as it was before ES5 (which is definitely not the last word).
Classes as sugar proposes to sweeten such "method definitions", to
lighten the boilerplate tax and reduce opportunities for nesting/
bracing/"this"-binding errors.
> I think they can live with writing .prototype when defining operators.
Your bikeshed is ugly and overlarge. :-P
> In fact I like the uniformity that you have to use the prototype in
> both cases.
No uniformity with instanceof, is that incipient revolution?
Perhaps just inconsistency for the sake of low-level explicitness, to
be as fair as possible. Or possibly pedantry, but again: if user-
defined constructor .prototype references are used and neither the
constructor binding in its scope object nor the .prototype property
are non-writable and non-configurable, then what is the point?
If the "type" name and .prototype *are* locked down (as with classes
as sugar), then there's no good reason for .prototype, it's just a
"syn-"tax and an unjustified inconsistency with respect to instanceof.
> Note that library users won't see this, only the library
> implementer. In any case, what users will "cry out for" is
> speculation.
We're talking about UI now, so user wishes count. And my bikeshed is
prettier and smaller -- I invite others (Tucker can recuse himself ;-)
to weigh in.
function "+"(a :Point, b :Number) {
return new Point(a.x + b, a.y + b);
}
function "+"(a :Number, b :Point) {
return new Point(a + b.x, a + b.y);
}
function "+"(a :Point, b :Point) {
return new Point(a.x + b.x, a.y + b.y);
}
I'm not sold on Dylan's \+ (backslashes are troublesome and
overloaded), but like quoting, it is a clean extension to the grammar.
>>> Whether or not A's '+' operator uses 'this', it's still a part of
>>> A's
>>> behavior and the most consistent place to put it is where A's other
>>> behavior is, its prototype.
>>
>> Could be, or one could use an optimized multimethod matrix, or some
>> other
>> implementation approach. Again I do not see why the spec should
>> dictate
>> observable prototype properties, internal or otherwise. If it just
>> uses this
>> model but keeps it concealed, then I'm ok with it provided we don't
>> close
>> the door on multimethods prematurely.
>
> JS allows introspection and self-modification and both are widely used
> and cited as advantages of the language.
Self-modification is widely criticized too, even in this thread. See
Allen's measured post on Smalltalk history. Monkey-patching bites
back, the ability to do it is a mixed blessing.
I chose to make most things mutable in Netscape 2 (even built-in
constructor.prototype, if memory serves) because I had too little time
to get the core language right, and I knew users would need to monkey-
patch. That was then. As noted earlier in this thread, with ES5's
Object.freeze etc., it will become harder over time to count on the
ability to monkey-patch.
> I would want to extend that
> to cover operators as well.
Why? I'm asking for specific use-cases, e.g. one-off or otherwise ad-
hoc operator bindings.
You still haven't addressed the ==/=== relation and other "value type"
issues such as literal notation extensibility.
> Having an internal property with some
> associated utility methods on Object is a nice way to get that.
The internal property is invisible to users of the language, and could
be replaced by other implementation techniques. That's why I question
it as a spec device.
You really did propose symmetric multimethods, but hooked them up
"backstage of the language" using "this+" and "+this", etc. At this
stage I contend we should focus on the fundamental design elements
including multimethods, and not on the ES1-5-style internal property
spec hacks.
And of course prettier, more usable bikesheds are fair game, if anyone
wants to comment. Operators and other value type extensibility are
motivated by usability problems with functions and methods and numeric
literals jammed into strings.
/be
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20090703/059b074d/attachment-0001.html>
More information about the es-discuss
mailing list