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:
|
02:50 | <jschoi> | Don’t we want to throw at step 4 anyway if Symbol.iterator is missing? |
02:50 | <bakkot> |
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 |