three small proposals: the bikeshed cometh!

Brendan Eich brendan at mozilla.com
Thu Apr 29 12:47:26 PDT 2010


On Apr 29, 2010, at 12:11 PM, Alex Russell wrote:

>> One wag replied after I had people vote on these "what about voting  
>> on
>> function"? Many hands then went up, more than for any of the above.  
>> This set
>> the cat among the shorthand-promoting pigeons.
>
> None of the options you provided had the contours of the proposed
> solution, so it's not clear that the lack of support for your
> proposals commutes to lack of support for this one.

Define "contours" -- do you mean # instead of λ or ƒ, or the  
(separate, I agree, but problematic) completion-value is implicit  
return value idea? We've discussed both here over the years, but I  
admit my two straw polls at conferences didn't cover the latter.


>> var boundMethod = obj!method;
>> node.addEventListener("click", obj!method);
>> node.removeEventListener("click", obj!method);
>>
>> There's some precedent for ! as non-blocking send, returning a  
>> promise.
>
> In ES? Which implementation? And is that the only objection?

Hey, don't sweat it -- I'm not your court of last appeal. We're here  
merely to discuss, so I was just noting a precedent from other  
languages that has been cited recently in connection with JS (e.g., at http://es-lab.googlecode.com/files/dr-ses.pdf) 
.


>> NodeList.prototype.parents = function() {
>>    // should return a NodeList
>>     return this.map(function(n) { return n.parentNode; });
>> }
>>
>> IIRC a NodeList is a "live array", sort of a query-as-array or  
>> cursor that
>> is continuously updated when the DOM mutates. It's really not an  
>> Array.
>
> Not today, but changes like this set the groundwork for turning
> NodeLists into real arrays. More to the point, what's so funky about a
> "live array" anyway? All Array objects in the language are "live". The
> idea that you'd have some array that's *not* subject to mutation is
> the oddball, not the rule.

The mutation happening behind your back is what makes NodeLists quite  
different from Arrays. I can make an array instance, keep it isolated,  
and its length won't change. I believe that's not true of a NodeList  
(because it's not truly isolated from the DOM whence it came). Please  
correct me if I'm mistaken.


> I'm not claiming that we should do anything about types in this
> proposal. I'm explicitly ONLY asking that when you call one of the
> Array generics through an object that has a mutable length property
> and some agreed upon way to add elements (push?), that they return new
> isntances of the caller's type, not Array.

You said "subtype" ;-). Me, I'm happy with any term so long as it is  
well-defined, which so far your use of "subtype" is not.


> That's *all* I'm asking for. Discussion of types, relationships
> between types, etc. is a distraction from the actual proposal and I'm
> sorry I ever used the word "subtype".

No problem.


>> In this case it seems to me you might want the result of Array  
>> generics to
>> be created by calling (new this.constructor). For nas.slice(0), the  
>> generic
>> slice code would then put elements got from |this| into the result  
>> of (new
>> this.constructor). Is this the spec you want?
>
> Yes.

Ok then!


>> Dave Herman has recently
>> proposed http://wiki.ecmascript.org/doku.php?id=strawman:let_expressions 
>> ,
>> which include an explicit "completion value here" prefix: => 10; in  
>> tail
>> position would result in 10, and without => the result would be the
>> undefined value.
>
> Seems reasonable.

EIBTI.


>> * equivalent semantics to the function(){} syntax
>>
>> No, not equivalent because tail position completion values are not  
>> return
>> values with functions. Again semantics matter, not just syntax.
>
> As noted, that's optional. I'm not tied to it. All I care about for
> this proposal is to shorten "function" to "#". The other options where
> added there as (apparently unclear) illustrations of how other changes
> might make such a syntax even better.

Is # the winner in your view, over all other one-letter alternatives?


> One point I didn't bring up was that the new bang operator doesn't
> allow for partial argument application, ala Function.prototype.bind.
> Seems a minor loss to me since all the other syntaxes I could think up
> that would have allowed it feel cluttered.

We prefer orthogonal primitives that compose well, so long as the  
composing doesn't drag in the big mandatory library that you rightly  
decry. Usability matters too; sometimes a compound built-in is  
warranted (even Mark agrees, see const f(){...} which binds f as a  
const in its block, freezes the function object, and for all I know  
does something else to boot! ;-).


> Yeah, I considered it. I'd be just as fine with wrappers having
> bound-to object lifetimes (as in my sample).

This is least surprising, but see my followup about method syntax to  
optimize prototype sharing and avoid a million sprite moveTo bound  
method objects for a million sprites.


>> Apart from the ! as promise-send and weak-vs.-expando issues, the big
>> objection here is that you make each reference specify bound-ness and
>> require memoization on the fly. An alternative would be to bind at  
>> method
>> definition point. Then you could only extract the bound method, no  
>> matter
>> how used, and via the conventional . operator. See
>> http://wiki.ecmascript.org/doku.php?id=strawman:obj_initialiser_methods
>
> This is really terrible. You don't know when you're going to get a
> bound result or not, so as a user you're back to the same "guess what
> kind of function it is and always call bind() anyway" games.

It's not a complete proposal, so be gentle. Whether and how the method  
would be bound is an open issue, but everyone is aware of the problem  
with lack of binding.

Your solution puts the binding burden on the programmer at each point  
of use, rather than at the definition. I'm arguing for the definition  
(whatever the syntax) to imply bound-ness, and enable optimizations  
(with identity not preserved on extraction).


> The new
> operator always ensures that you'll get *a* bound function, even if
> what you're currently binding to isn't exactly what you think it is
> (which is somewhat rare).

Yeah, but the method definer often wants all uses to behave as if  
bound, and the degree of freedom your proposal adds is strictly  
unwanted. As I noted in my last post, it also complicates the surface  
language and increases the cognitive load on users of methods (not  
definers), who are more numerous and less skilled ("what do I use, '.'  
or '!'? Crock says '.'! :-P).


>> i'm against "invoke-only" methods, but bound method definition  
>> syntax is
>> easier for users and implementors to swallow, and preserves dot as  
>> the one
>> operator needed for extraction. It would also make the method  
>> reference
>> strong, which would avoid the too-weak loss of expando problem.
>
> We can solve that without furthering the ambiguity of the dot
> operator, which is the primary problem to be solved here.

The . operator is not ambiguous in any sense I know of. The issue is  
not simple and one-sided, user-of-dot-only. Do I, the Sprite library  
author, always bind? If so, how efficiently? Do you, the consumer,  
have to bind out of paranoia? (No, if we give the library author the  
tool to prebind.) Do you, the library user, need to choose between '.'  
and '!'? I claim not.


> I don't
> consider proposals that leave "dot" ambiguious with regards to binding
> to be of any real use.

That's a loaded formulation, given the different interests of  
abstraction producers from consumers. It's also a bit confrontational,  
as if I wrote "I don't consider proposals that confuse users with  
another '.'-like operator to be of any real use". :-|

I did write this:

>> Glad to see this proposed for discussion -- good suggestions,  
>> directionally
>> and in some details.
>> /be

So, be nice.

/be


More information about the es-discuss mailing list