02:38
<jschoi>
Regarding Array.from: In https://tc39.es/ecma262/#sec-array.from, why is usingIterator created in step 4? Wouldn’t GetIterator(items, sync) in step 5c do the job of checking for a sync iterator and throwing TypeError if it can’t? (What is even the purpose of the third parameter of GetIterator?)
02:40
<jschoi>
Is it to maintain a specific order of attempting to construct C, then calling GetIterator?
02:43
<bakkot>
GetIterator unconditionally attempts to call the Symbol.iterator property, even if it's undefined, whereas Array.from needs to not enter step 5 at all if the Symbol.iterator property is undefined
02:43
<bakkot>
the purpose of the third parameter of GetIterator is in case you have already done the property lookup of Symbol.iterator, to avoid doing the property lookup again
02:44
<jschoi>
Right, and I suppose this is observable by the user, because they can observe whether Construct(C) is called before Symbol.iterator.
02:44
<bakkot>
It's not just about order; it's about only accessing the property once
02:45
<bakkot>
e.g. if you have a getter for Symbol.iterator, Array.from should only invoke that getter one time
02:45
<jschoi>
Ah, okay.
02:45
<jschoi>
Thanks!
02:46
<bakkot>
I don't think we actually cared much about the order of the call to C vs to Symbol.iterator, but we definitely do care that the property is only accessed a single time
02:46
<jschoi>
I guess I’m confused why step 4 isn’t what step 5c currently is.
02:47
<bakkot>
uh
02:47
<bakkot>
I don't know what that means
02:48
<jschoi>
Another way to put it: why would “Let iteratorRecord be ? GetIterator(items, sync)” result in two accesses of item’s Symbol.iterator property?
02:48
<bakkot>
oh, you mean, why is step 4 not GetIterator? it's because GetIterator unconditionally attempts to call the Symbol.iterator property, even if it's undefined
02:48
<jschoi>
Mm, yeah, I see now that’s true in GetIterator’s definition. That’s a bit surprising. It does check that the result of the Symbol.iterator-value’s function call is an object.
02:48
<bakkot>

that is, there's two things happening here:

  • step 4 can't use GetIterator because GetIterator will throw if Symbol.iterator is missing
  • step 5c needs to forward usingIterator so that it doesn't do another access of Symbol.iterator
02:50
<jschoi>
Don’t we want to throw at step 4 anyway if Symbol.iterator is missing?
02:50
<bakkot>

That’s a bit surprising.

Eh, so, most of the APIs in JS take only one kind of thing. if they take an iterable, then they're expecting an iterable, and throwing if you pass something non-iterable is the right behavior.

Array.from is relatively unique in that it also accepts an array-like, because it's specifically intended as a coercion method to turn your array-likes into actual arrays (which can then be passed to things which take iterables, because arrays are iterables)

02:50
<jschoi>
Oh wait.
02:50
<jschoi>
Of course, right, I had forgotten about that behavior.
02:50
<jschoi>
Array.from does not take only iterable inputs.
02:50
<jschoi>
It’s been a long day; thanks for your patience!
02:51
<bakkot>
nw, happy to help