lexical for-in/for-of loose end

Allen Wirfs-Brock allen at wirfs-brock.com
Thu Feb 2 15:52:59 PST 2012


On Feb 2, 2012, at 1:38 PM, Brendan Eich wrote:

> Allen Wirfs-Brock wrote:
>> On Feb 1, 2012, at 7:13 PM, Brendan Eich wrote:
>>> ...

Unfortunately, having thought about it a bit since the meeting, I'm less convinced. We didn't look too deeply at possible capture scenarios such as:

let geti;
for (let i=(geti = function() {return i},expr), expr, incr = function(i++), decr=function(i--), cmp=function(){return i<n}; cmp();incr()) {
       let j=i;
       i +=10;
       decr();
       ...
       If (j+-9 !== i) ...
       ...
}

>> ...
> 
> keys etc. are currently spec'ed to to do own-only, you want allKeys to do the crazy thing:
> 
> http://wiki.ecmascript.org/doku.php?id=harmony:iterators#standard_api
> 
> Let's not go around and around on this. Enumerable proto-properties are harmful, no one wants them.

I'm afraid I have to disagree with the absolutism of this statement.  There are some perfectly reasonable use cases for enumerating proto properties and they are quite in alignment with prototypal inheritance.  For example, how about defining a set of default property values and then using prototypal inheritance to selective over-ride them:

let privateImplicitOptions = {a:1,b:2,c:3 /* and on and on */};

function makeOptions(explicitOptions) {
    let opt = Object.create(privateImplicitOptions);
    for (let [k.,v] of items(explicitOptions)) opt[k]=v;
    return opt;
}

myOpts = makeOptions({b:-2});

Why should somebody I pass an options object to need to worry about whether I used zero, one, or n levels of prototypes to represent by options.

that said, I think we agree that the real problem is the legacy ES semantics of for-in and its use (or lack of) for the enumerable attribute. If we can start out with a clean slate conceptual slate for for-of maybe we don't have to worry about such things.  However, carrying over a lot of historic baggage isn't a clean slate.  Thinking in terms of abstract collections, having keys() not mean "all keys in the collection" seems quite absurd.  That should be the normal case, the more verbose name should be used for the exceptional case that excludes some of the keys.  Now in this case, the real problem is in deciding the default way to view a plain Es objects as an abstract collection. Maybe only considering own properties  as the collection elements is the right thing.  In that case it may be "allKeys" that is carrying the wrong implication and instead it should be something like "extendedKeys".

> ...
> 
>> Presumably, the only prior leaning that applies comes from CoffeeScript.  While CS is popular, it isn't at all close to being used by the majority of JS developers.  CS experience is informative but I don't think we have to worry so much about CS derived habits.
> 
> It's informative, agreed, and competitive -- my point. TC39 does poorly inventing new and untested API. We do better paving cowpaths. I think we should be careful not to get too far ahead of de-facto standards, while avoiding being hostage to language design flaws from the past. We also should not oversell Smalltalk, etc. -- Smalltalk is informative (your collections port especially) but not particularly more important (or less) than CS.

Totally agree concerning Smalltalk  other languages.  However, when we are looking to extend into new areas it makes sense to look at languages that excel in those areas. We're talking about making ES a better to define object-based abstractions and in specifically in this thread collection abstractions. That is an area where we can learn a lot from Smalltalk.
> 
> ...
> 
>> There is still a default.  The iterators proposal says that for-of falls back to @enumerate if @iterate isn't present.
> 
> That's a proxy trap, and I believe that dates from before for-of. We need to revisit this now, based on splitting iteration out to for-of and leaving for-in the old enumerating mystery meat that it has always been. Cc'ing Tom.
> 
> It's important to distinguish property default from proxy trap built-in.

Not sure, I understand why.  Presumably the default behavior of a proxy trap should be the same as the built-in behavior.  The internal methods (which need to be extended to include things like [[Interator]]) have a specification for  "normal" objects and an alternate one for Proxy objects that just invokes the trap.  However, the default traps handlers should be specified to turn around and invoke the corresponding "normal" internal method.

> 
> If there's an Object.prototype. at iterator that iterates values, or [key,value] pairs, or whatever, then we make it hard for new collections and set-like abstractions to do something slightly different.

I don't see where the hardness comes from.  They just need to define an appropaite @Interator method. They are going to have to do so regardless of whether a default @Iterator is defined on Object.prototype or whether the default is just hardwired (for example to throw).  In either case the default  needs to be over-ridden.
> 
>> BTW, this is a good example of something that should not be built into statement semantics.  Why should |for (v or values(o))...| iterate differently than |values(o).forOf({|v|...})|
> 
> Do you mean forEach?

No, I'm hypothesizing a new method that mimics for-of iteration. 
> 
> Who says values(o) returns an array? That is costly and the point of iterators is to use a lazy protocol. Indeed the

I wasn't implying that at all.  My point is that we want to able to easily write functions that do the same style of iteration as for-of.  Placing essential pieces of the for-of semantics (such as calling [[Enumerator]] if [[Iterator]] is not defined) into the evaluation algorithm of the for-of grammar production is not a good factoring from this perspective.

> 
> http://wiki.ecmascript.org/doku.php?id=harmony:iterators#standard_api
> 
> proposal has values a generator (returns an iterator).
> 
>> My currently thinking (working off of the current wiki proposal) is to have [[Enumerate]] and [[Iterate]] internal methods (for all objects) and it is in their default implementation that [[Iterate]] delegates to [[Enumerate]].
> 
> No, see above. We do not want to mix these up. Iteration via for-of uses the iteration protocol.
> 
>>> No issue here, I think. We want for (x of {p:1, q:2}) to throw, without the user first having defined @iterator in Object.prototype (and that would not be recommended practice).
>> 
>> Not what the wiki proposal currently says...
> 
> Where? 

http://wiki.ecmascript.org/doku.php?id=harmony:iterators#evaluation_of_for-of_loops 

but you're right the part of the algorithm I was looking at is clearly obsolete.  At this point, I think I'm probably better off just writing the for-of spec. from scratch.  It's actually pretty simple, it just calls the [[Iterate]] internal method to get a iterator instance and then has be boil plate to of looping using tht iterator.  All the defaults, @iterator overrides, proxy support, etc is taken care of via [[Iterate]]


Allen
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20120202/0811b1b6/attachment-0001.html>


More information about the es-discuss mailing list