19:15
<bakkot>
TabAtkins: the way you've written https://webidl.spec.whatwg.org/#es-map-iterator implies that (new Map)[Symbol.iterator]().next.call(webIdlMapLike) would work, which is... maybe not a thing you intended?
19:15
<bakkot>
I don't know where webidl map-likes are used though
19:16
<TabAtkins>
Hmmmmm, I dunno if that's a problem?
19:16
<TabAtkins>
(For an example usage, see https://tabatkins.github.io/css-toggle/#dom)
19:18
<bakkot>
I think that is... probably not desirable, at least for implementations?
19:18
<TabAtkins>
.next() isn't usable directly on a Map, right? You'd still have to actually extract an iterator, which has .next() from its proto.
19:19
<bakkot>
oh, yeah, so (new Map)[Symbol.iterator]().next.call(webIdlMapLike[Symbol.iterator]())
19:19
<bakkot>
I think you probably do not want to require that that work
19:19
<TabAtkins>
Why not? Making it not work would presumably require us to not use MapIteratorPrototype at all, right?
19:20
<bakkot>
oh, I missed that you are intending to use MapIteratorPrototype
19:20
<TabAtkins>
(That was already required before my edits, btw.)
19:21
<TabAtkins>
Yeah we're manually reproducing Map's proto methods by hand, but there's no reason for us to do the same for its iterator.
19:22
<bakkot>
it's conceptually kind of weird? a "real" map iterator uses the [[MapData]] internal slot
19:23
<bakkot>
I don't think it's going to cause problems for users (or even be noticed), but it might trip up implementations
19:23
<bakkot>
when we wrote https://github.com/tc39/ecma262/pull/2045 the thinking was that brands would be single-use
19:24
<TabAtkins>
If that's problematic, the spec shouldn't be written in a way that implies it's pluggable. ^_^
19:24
<bakkot>
the spec is not an API
19:24
<TabAtkins>
what's this about brands?
19:25
<bakkot>
the string argument to CreateIteratorFromClosure is a brand
19:25
<bakkot>
which is intended to prevent users from using .next from one kind of iterator with a different kind of iterator
19:26
<TabAtkins>
Oh, if that's the issue we can change that.
19:26
<TabAtkins>
It didn't look like something I needed to change, is all.
19:26
<bakkot>
if you change it you'll also need a new prototype, though
19:27
<bakkot>
the way it works is, CreateIteratorFromClosure specifies a brand, which is stored on the iterator, and then the various .next methods check that brand
19:27
<ljharb>
please do not reuse MapIteratorPrototype on something that's not a Map, that's not right
19:28
<bakkot>
so CreateMapIterator and %MapIteratorPrototype%.next ( ) both specify the "%MapIteratorPrototype%" brand, which is how we achieve that only the MapIterator .next works with map iterators
19:29
<ljharb>
and it would be a bug if that brand check passed on something that wasn't a Map instance
19:29
<bakkot>
ljharb: the brand check is only for Map iterators, not Map instances
19:30
<ljharb>
oh right sorry
19:30
<ljharb>
ok, Map iterator instance then :-p
19:30
<ljharb>
(obv that's way less important to brand check)
19:31
<bakkot>
TabAtkins: anyway, if you want to avoid re-implementing stuff, while also not pretending to be an actual Map iterator, I think the simplest thing would be to pretend to be a userland generator - i.e. inherit from Generator rather than MapIterator, and use ~empty~ as the brand
19:31
<bakkot>
this has the bonus that it would allow implementations to implement the iterator as a JS generator
19:32
<TabAtkins>
Hm, that would mean that future things put on MapIteratorPrototype wouldn't apply then, right?
19:33
<bakkot>
well, so
19:33
<bakkot>
as long as MapIteratorPrototype is written as a spec generator, it can't really have more things put on it - the state is all internal to the closure created in CreateMapIterator
19:34
<bakkot>
so if we wanted to add more stuff, we'd have to revert the change from https://github.com/tc39/ecma262/pull/2045 anyway
19:34
<bakkot>
and go back to using specialized slots on the iterator instance to store the state of the iterator
19:34
<bakkot>
which would break this part of webidl anyway
19:35
<ljharb>
why would MapIteratorPrototype ever get something added to it? iterator helpers would be on a superclass, and generator-made iterators would have those too, i think
19:35
<bakkot>
java's iterators have a remove method which is occasionally handy, e.g.
19:35
<bakkot>
I don't think we'd want to add it but we conceptually could
19:36
<bakkot>
for iterators for collections in particular, and not for arbitrary generators/iterators
19:36
<TabAtkins>
Right, I was thinking about iterator helpers. But if they'll all show up on something that all userland generators get too, then I suppose my concern is moot.
19:36
<ljharb>
it.remove() as a shorthand for "get the key and remove it directly from the collection"?
19:36
<bakkot>
yup, iterator helpers add things to the root iterator prototype, which is shared by MapIterator and also the iterators produced by userland generators
19:37
<bakkot>
ljharb: in java it means "remove the last thing yielded"
19:37
<ljharb>
weird, ok
19:37
<TabAtkins>
def weird
19:38
<bakkot>
TabAtkins: actually wait, forget my suggestion about inheriting from generator, though
19:38
<bakkot>
that would have other consequences which are bad
19:38
<bakkot>
because generators also have .return which injects a return completion at the current yeild, which is... not a thing you want, almost certainly
19:40
<TabAtkins>
I mean, userland generators have to deal with that too, right? Is there a simple way I can, like, intercept and either ignore it or bail or something?
19:40
<TabAtkins>
(I'm willing to do a lot if it means (a) I don't have to redefine the entire interator infrastructure from ES and (b) iterator helpers will still work.)
19:41
<ljharb>
i think you probably should just make your own iterator thing that inherits from Iterator.prototype (which will make helpers work), just like map/string/set/etc are their own thing
19:41
<bakkot>
userland generators do have to deal with it but the problem is that you have to think about it at all
19:41
<bakkot>
.return just doesn't exist on map iterators
19:41
<bakkot>
anyway yeah, I think I would just add a new iterator prototype, like MapIteratorPrototype. that's what the language would do at least.
19:42
<bakkot>
you can copy-paste the whole of the MapIteratorPrototype clause; it's actually quite short now
19:42
<TabAtkins>
yeah, https://tc39.es/ecma262/#sec-%mapiteratorprototype%-object is doable
19:42
<TabAtkins>
okay, sigh, thought i was done with this edit but back into the breach
19:45
<bakkot>
apologies
19:52
<TabAtkins>
So just to be clear, the overriding issue here is that, in practice, the second and third arguments to CreateIteratorFromClosure (giving the brand and prototype) should be unique per call site, more or less?
20:05
<bakkot>
I would put it a different way: if the second and third arguments are not different, you are saying that these two things are actually the same thing, even though they have different behavior, and you should be really sure you want that