three small proposals: the bikeshed cometh!

Mike Samuel mikesamuel at gmail.com
Thu Apr 29 11:34:19 PDT 2010


2010/4/29 Brendan Eich <brendan at mozilla.com>:
> On Apr 29, 2010, at 12:25 AM, Alex Russell wrote:
>
> Some small, pre-colored panels for the shed. Given that these are mostly
> matters of syntax and not semantics, please believe me when I suggest that
> the warts discussed herein present sharp edges that should be rounded off by
> the committee -- not because they're interesting in any way but because the
> primary users of the language are shipping (bad) fixes around the network
> billions of times a day. Such rank inefficiency needs sunset date.
>
> This is not just about syntax. Let's ignore the threat of being accused of
> bikeshedding and evaluate holistically.
>
> Summary of proposals:
> ---------------------
>
> // 1.) Really generic generics
>
> ArrSubtype = function() { };
> ArrSubtype.prototype = Object.create(Array.prototype);
>
> var nas = new ArrSubtype();
> nas.push("howdy", "pardner");
>
> nas.slice(0) instanceof Array; // currently true
> nas.slice(0) instanceof ArrSubtype; // will be true after fix
>
> An incompatible change, but would it break much code? Hard to say without
> trying it at scale. Here are some codesearch results:
> http://www.google.com/codesearch?hl=en&lr=&q=%22prototype+%3D+[]%3B%22+lang%3Ajavascript&sbtn=Search
> http://www.google.com/codesearch?hl=en&lr=&q=%22prototype+%3D+new+Array%3B%22+lang%3Ajavascript&sbtn=Search
> How would it work exactly? More below on "subtyping".
>
> // 2.) Shorthand for "function", aka the "not lambda"
>
> node.addEventListener("click", #(e){ e.preventDefault(); });
> node.removeEventListener("click" obj!#(e){ ... }); // see #3
>
> The hash or number sign is not obviously all about functions. I've tried out
> the other alternatives in recent talks. No one is really enthusiastic about
> any of
> λ foo() (bar + baz)
> ƒ foo() (bar + baz)
> \foo() (bar + baz)
> (the foo name is optional but should be expressible).
> The Greek lowercase lambda is actually an incompatible change from ES3
> (perfectly legal identifier there). It's also hard to type on most
> keyboards.

I'm not arguing for lambda since it is a pain to type, but this is not
true if you make it a restricted production, and make the name non
optional
    <lambda> (no line separator) <identifier>
cannot appear in a valid ES3 program.


> The florin is easier (alt-f on my Mac) but maybe a bit visually light and
> hard to scan for quickly, and it's arguably harder for newcomers to divine
> its meaning.
> The \ does not make much sense, but it was proposed first among all of these
> on es-discuss, IIRC.
> 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.
>
> // 3.) Shorthand for Function.prototype.bind
>
> 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.
>
> 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.
>
> * Kill code in libraries that exists only to wrap built-in methods thanks to
> existing mis-specification of generics
> * Sub-types of Array suffer many warts, but making Array.prototype methods
> return instances of subtypes will allow DOM-side changes to make subtyping
> much more natural in real-world systems
>
> "Subtype" is not well-defined in JS. Prototype-based delegation is not the
> <: relation from type theory, because of mutation, both of the prototype
> object and of the future binding of f in a scope and f.prototype in
> user-defined function f.
> This isn't just a pedantic point. If we don't have a well-defined relation,
> how can we evaluate proposals that want to improve support for that
> relation, whatever it is?
> 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?
> If so, it seems like an improvement, but again constructor has low integrity
> (none for user-defined constructor functions) without freeze, so there's no
> subtype relation in the formal <: sense. Still, it seems to me an
> improvement, ignoring the incompatibility.
>
>  // equivalent:
>  function(){ return 10; }
>  #(){ return 10; }
>  #{ return 10; } // no args, optionally elide ()
>
> This does several things at once, and we have discussed one of them: turning
> the completion value of the body into the return value.
> The objection to this, voiced clearly by Waldemar, is the unintended
> completion value in tail position leaking out as a return value. This is
> hard to see and test for, and it requires ugly void operator usage, or a
> dummy final value, to control.
> 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.
>
> * 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.
>
> 3.) Syntax for bound function de-reference
> [snip] So why does this suck? Two reasons: it's long-ish to type, and it
> doesn't do what the dot operator does -- i.e., return the same function
> object every time.
>
> The lack of memoization is a good point. I've written at length about the
> challenges for implementations to "join" function objects as an
> optimization:
> https://mail.mozilla.org/pipermail/es-discuss/2010-February/010830.html
> https://mail.mozilla.org/pipermail/es-discuss/2010-February/010832.html
>
> What to do? We propose the bang operator -- ! -- as a new form of binding
> de-reference of function objects. It's one character and even includes a
> dot.  It has the following additional properties:
>
> 1.) all de-references via bang from an object/function pair return the
> *same* function object (modulo #4).
> 4.) bang-bound functions are weakly referenced. If GC would otherwise remove
> a function object from memory, having previously bang-bound a function
> should not keep the function object alive
>
> This is a tricky area. We have experience with such ephemeral objects.
> Problem is, sometimes users decorate them with ad-hoc properties
> ("expandos"), which by your proposed rules will not keep them alive. The GC
> runs, and the decorator is surprised to see the ad-hoc properties gone.
> 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
> 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.
> Glad to see this proposed for discussion -- good suggestions, directionally
> and in some details.
> /be
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>
>


More information about the es-discuss mailing list