Allen Wirfs-Brock wrote:
On Feb 1, 2012, at 3:31 PM, Brendan Eich wrote:
Brendan Eich wrote:
It's never inconsistent to allow one thing and disallow another. The
particulars matter. This isn't "anything goes". Destructuring has a
bit of utility and a lot of regularity in for-in head position. The
initialiser from VariableDeclarationNoIn has neither specific
utility nor regularity with respect to for-in in AWK, Python, or any
other language with such a construct.
More to say, I sent too soon. Don't take this as more than it is: an
attempt to explore an alternative meaning of for-in combined with
certain destructuring patterns.
We have a request that seemed to receive popular support, to support
for own (k in o) ...;
This could compose with the following nicely, and it tries to pave
the CoffeeScript cowpath a bit (without taking CoffeeScript as
normative or overriding or anything like that).
Towards the end of
https://mail.mozilla.org/pipermail/es-discuss/2011-November/018332.html I
made an argument that own-ness of properties is an implementation
choice that normally should not be of concern to application clients
of an object-based abstraction. Own-ness is primarily relevant to
abstraction implementors or somebody who is using reflection to
examine the implementation structure of an object.
That's an ideal but the reality is for-in and easy transpilation from
better derived forms to it are with us, and will be for a while.
Hopefully reflection is tucked away in a obscure but pleasant corner
of the language and not widely used for routine application logic.
Generally, reflection doesn't deserve (or require) statement level
support.
still want easy array-value iteration. That's what for-of does out of
the box. This is important, it shouldn't take any more chars than
for (v of a)...
eliding declaration of v and decl/init of array a.
That raises the question of the role of the for-in statement in the
language (besides just being an obsolete and less useful alternative
to for-of). Being a full fledged syntactic statement of the language,
it certainly isn't hiding in an obscure corner. If we want to think
of it as something other than an over exposed reflection tool, what is
it for?. The best expression of this that I can come up with, is that
for-in is a statement that is primarily useful for iterating the "data
member keys" of simple record and array like data abstractions.
So far, so good, and latent here is the best case for not elaborating
the left-hand side to include destructuring, if you can avoid bloating
the grammar too much. Contra my "regularity plus small use-cases"
argument, we leave for-in alone. We can even leave it underspecified as
in ES5.
From that perspective, own-ness again is something that should
primarily be an implementation concern.
Historically this came up because pre-ES5 people couldn't extend
Array.prototype, e.g., without making enumerable properties. But of
course then the wisdom said don't use for-in on arrays. Object.prototype
is verboten, and at some cost in using custom functional-programming
style iteration, we're ok (PrototypeJS status quo).
The problem that may remain is that
for own (k in o) ...;
still beats
for (k in keys(o)) ...;
not only by a couple of chars not counting import or assuming prelude,
but in terms of people's historical memory and folk-wisdom learning.
Should we ignore all this and say "just use for-of with the right iterator?"
To me, for-own-in makes it too easy for client code to create
dependencies upon what should inconsequential implementation decisions.
In reality the shoe is on the other foot. Implementation decisions that
should be without consequence mess up for-in, requiring hasOwnProperty
testing. People want a shorter-path solution.
Giving a longer-path solution with for-of and iterators is good, we want
that. Is it good enough to be the only solution we build into the language?
We have a goal of making ES a language that is better for creating and
using abstractions. For-own-in is a tool that tunnels through
abstractions.
I think you're making too sweeping a statement about abstractions. Does
for-own-in tunnel in ways that violate abstractions, or is it really
what the doctor ordered for JS close to today's best practices (not
always followed)? I say more the latter, but not clear cut in any event.
Such a tool is fine as part of the reflection facility, but making it
a full fledged statement seems like it would be creating an attractive
nuisance.
We have a full-fledged statement, for-in. It can't be deprecated quite
yet. Adding for-of helps, but is it enough? That's the issue I'm raising.
We could make just-so meanings for destructuring in for-in, also
inspired by CoffeeScript (and JS1.7, which did this too while
muddying the waters by failing to separate iteration protocol into
for-of):
for ([k, v] in o) ...;
Clearly, this isn't a general destructuring. It is a special
syntactic form that is mimicking array destructuring syntax. We could
probably have a long thread about whether such mimicry is clever
language design or a confusing creole. I reserve my opinion on the
general questions.
Yes, and CoffeeScript does not use [], so it has a special form: for k,
v of o ....
I think overloading the [k, v] pattern this way is a mistake, and I'm
not ready to propose []-free comma-separated key and value special
casing. Again, es-discuss thought-experiment here, not
strawman:melt_allens_brain ;-).
Our current position is "use for-of and an items helper function":
import items from "@reflect"; // currently @iter; could be part of
standard prelude
for ([k, v] of items(o)) ...;
see the main part of the message I referenced above. Pure functional
filters like item are unfriendly to collection abstracton builders.
JS has little of the OO collection building you see in Smalltalk or
Java. Is this a bug in the language and communities using it? I'm not so
sure.
Your point that we want functional helpers to delegate to OO methods is
well-taken, and IIRC that's what Python does. The proposal at
http://wiki.ecmascript.org/doku.php?id=harmony:iterators#standard_api
does not delegate from items(d) to d.@items or whatever it ought to be
called, but this is easy to add. Cc'ing Jason for his thoughts.
But I think detailing the design of ES6 must be allowed to entertain
an even easier-to-use extension to for-in.
Another simplification would be to make default iterator produce
{key,value} item objects,
Then we have three concise formulations:
for ({key, value} of o) ...;
for ({key} of o) ...;
for ({value} of o) ...
No, too expensive. We want just the keys or just the values, often
enough. Narrow is better than wide.
If you want values not keys, then per the current proposal you use
for (v of values(o)) ...;
given the necessary values import, or inclusion in a standard prelude.
There's a hole vs. CoffeeScript: we do not want for-of on a plain
Object to iterate over enumerable property values. Arrays, yes,
Objects, no -- no Object.prototype.@iterator. So no |for (v of o)
...| for o = {p:1, q:2, r:3}.
(I note at this point that there are some huge es-discuss threads on
topics such as the above for which the conclusions (if any) have not
been extracted. I'm starting to go over them to see what I can extract
from them)
I assume that you are arguing that the default @iterator for
Object.prototype (however it is provided)
No! I clearly said there is no @iterator in Object.prototype.
does a key enumeration just like ES1-5 for-in. Or are you arguing
that it produces nothing?
No @iterator in Object.prototype. We've been over this, Jason argued
convincingly against pre-defining one because it is future-hostile to
collection iteration.
I'm not exactly sure why either of those is better than |for (v of o)
...| but I think there are a couple threads that I need to digest that
drill into the issues.
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).
Also no for each (v in o) as E4X (ECMA-357) promulgated. SpiderMonkey
and Rhino support it and probably will have to carry it, but such
"each" does not say its meaning (values not keys) clearly, and it
doesn't compose with "own" nicely.
But with destructuring for-in, you could write
for ([, v] in o) ...;
currently the grammar don't support the above hole syntax. I wouldn't
be a support for adding it.
Wait, holes are useful in destructuring array patterns, to avoid dummy
bindings. We support holes in array destructuring in JS1.7 up. What is
the problem? Saying the grammar doesn't support holes and you don't
support them is no explanation.
This is a bit ugly (holes never look pretty, even when they're useful).
Not sure what I think of this but I thought I'd throw it out here on
es-discuss. The reason I bring it up is twofold: 1) for own (k in o)
still needs to be discussed; 2) the for ([k, v] of items(o)) ...; tax
is a bit higher than I'd like.
and I'm trying to write spec. language for all of this right now, so
it is a good time to make some decisions.
Quoting Jason's reply in the thread you cited:
To address Allen's original question:
I think the Map and Set classes in Harmony mean that not all
structured data is stored as object properties. I think that's a good
thing.
However it does mean that we must have a separation of concerns between
- iterating over a collection
- object property inspection
...because I don't see how 'for (p of obj)' can be both the right
syntax for walking an arbitrary object's properties *and* the right
syntax for walking a Set's elements. Someday the "arbitrary object"
will be a Set. And then what?
So if we take that separation of concerns as our maxim, what do we end
up with? Here's a sketch.
Basics:
for (v of arr) // each element of an Array
for (v of set) // each value in a Set
for (k of map) // each key in a Map, following Python
Host objects / libraries:
for (elt of document.getElementsByTagName('P')) // DOM
for (elt of $("div.main p")) // hypothetical jQuery support
Other styles of iteration:
for ([i, v] of arr.items()) // index-value pairs (new Array method)
for ([k, v] of map.items()) // key-value pairs
for (v of map.values()) // just values, no keys (uncommon use case)
Enumerating properties:
import * from '@inspect';
for (p of keys(obj))
for (v of values(obj))
for ([p, v] of items(obj))
Or if you don't want to import anything:
for (p of Object.keys(obj))
for (p of Object.getOwnPropertyNames(obj))
This makes Map slightly nicer to iterate over than Object. I think Map
is a better, less error-prone Map than Object anyway, so that's
appropriate.
-j
I think we are close, but not quite where we should be. If we define
keys, values, and items to work in terms of properties (they're
currently spec'ed using for-in under the hood), are we missing a chance
to make these universal for collections that have keys and values? Set
can have values only, but the idea is to delegate from function to OO
method (with private names @keys, @values, @items). Or do something better.
Less is more in our world, private name objects shedding syntax and
getting into ES6 is one example. But we then talked about experience
possibly justifying syntax too (I've used @ above). Could the same thing
happen with iteration? I don't want to overdesign (who does? wait,
stop...) but doing too little will just create obligatory library downloads.
/be
_______________________________________________
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss