[Bug 27008] "Initializing objects from iterables" needs syntax

# bugzilla at jessica.w3.org (3 years ago)

www.w3.org/Bugs/Public/show_bug.cgi?id=27008

Boris Zbarsky bzbarsky@mit.edu changed:

       What    |Removed                     |Added

             CC|                            |bzbarsky@mit.edu

--- Comment #1 from Boris Zbarsky bzbarsky@mit.edu ---

I'm not quite sure why you need that here. I mean, you need a definition of OpenEndedDictionary, but the iterable bit is handled by the sequence in that union, no?

Contact us to advertise here
# bugzilla at jessica.w3.org (3 years ago)

www.w3.org/Bugs/Public/show_bug.cgi?id=27008

--- Comment #2 from Anne annevk@annevk.nl ---

I was under the impression that this new concept from IDL introduced by Domenic replaced the need for that sequence/dictionary construct.

# bugzilla at jessica.w3.org (3 years ago)

www.w3.org/Bugs/Public/show_bug.cgi?id=27008

Boris Zbarsky bzbarsky@mit.edu changed:

       What    |Removed                     |Added

             CC|                            |domenic@domenicdenicola.com

--- Comment #3 from Boris Zbarsky bzbarsky@mit.edu ---

Oh, I see.

I don't think it does, in fact, since it assumes that you have an iterable and just want to initialize from it. But that's not what you have. You have either an iterable or a random non-iterable object, no?

So ignoring web idl for now, how would one implement this? First check for a Headers instance, fine. Then check whether your object is iterable. If so, you have two choices. You can do the sequence thing, which will snapshot the iterable, and then you init from that snapshot. Or you could do the "add map elements from iterable" thing, which will redo some observable work (like getting @@iterator from the object, though we could maybe change that to pass in the iterator getter, like we do for "creating a sequence from an iterable"), right?

Lastly, if your thing is not iterable, then you treat it as an OpenEndedDictionary.

So in terms of syntax, we'd basically need to introduce some "live iterator" type which would check whether the object has a non-undefined @@iterator and then either pass through just that object or that object and the @@iterator value, right? And then you'd replace the sequence you have here with this "live iterator" type and perform "add map elements from an iterable" in prose?

We could try to jam everything that "add map elements from an iterable" wants (at least the method name, but it's not clear to me how it should guess the destination object, or whether it should be explicitly specified) in the syntax, but then it ends up being pretty weird if someone uses that type in, say, a dictionary: at that point, what is the destination object?

# bugzilla at jessica.w3.org (3 years ago)

www.w3.org/Bugs/Public/show_bug.cgi?id=27008

--- Comment #4 from Anne annevk@annevk.nl ---

Please forget about the current IDL syntax for Headers. It is not important.

A Headers instance is iterable so we would not have to specialcase it. This is a bit slower, but that seems fine since it's not a critical path.

I thought a normal object would also be iterable and that Domenic's proposal would do the right thing for { "H" : "V", "H2" : "V2" }.

My question I guess is whether HeadersInit should just become an alias for "any" then or if we can do something better.

# bugzilla at jessica.w3.org (3 years ago)

www.w3.org/Bugs/Public/show_bug.cgi?id=27008

--- Comment #5 from Boris Zbarsky bzbarsky@mit.edu ---

I thought a normal object would also be iterable

It's not...

My question I guess is whether HeadersInit should just become an alias for "any"

I'd like to understand what the problem is with the current HeadersInit definition. ;)

# bugzilla at jessica.w3.org (3 years ago)

www.w3.org/Bugs/Public/show_bug.cgi?id=27008

--- Comment #6 from Domenic Denicola domenic@domenicdenicola.com ---

My intention was to use any, so as to avoid additional type-checks and coercions before invoking the "initializing objects from iterables" algorithm.

You could add some new type that has the same semantics as any, I guess, e.g. ProcessedInProse or something.

# bugzilla at jessica.w3.org (3 years ago)

www.w3.org/Bugs/Public/show_bug.cgi?id=27008

--- Comment #7 from Anne annevk@annevk.nl --- krijnhoetmer.nl/irc-logs/whatwg/20140627 has some of the context from my discussion with Domenic which leaded to that pull request.

The basic gist seemed to be that what we ended up with did not look like what the Map constructor from ES6 does.

# bugzilla at jessica.w3.org (3 years ago)

www.w3.org/Bugs/Public/show_bug.cgi?id=27008

--- Comment #8 from Anne annevk@annevk.nl ---

Domenic, why does it not handle this case: { "H" : "V", "H2" : "V2" }?

# bugzilla at jessica.w3.org (3 years ago)

www.w3.org/Bugs/Public/show_bug.cgi?id=27008

--- Comment #9 from Domenic Denicola domenic@domenicdenicola.com ---

ES6 maps take arbitrary objects as keys, so it needs to be [["H", "V"], ["H2", "V2"]] so that instead of "H" you can use { foo: "bar" } or something. This seems important in the general case for headers so you can do [["H1", "V1a"], "H1", "V1b"]].

It makes sense to allow the Headers constructor to be overloaded with a (non-iterable) object as well for the less-general case. Nothing in ES does this but you could follow a pretty similar pattern. In JS it'd probably be

function useHeaders(headersInit) {
  Object.keys(headersInit).forEach(key => this.set(key, headersInit[key]);
}

Now that I look at this more closely I think I see why you desire syntax. Here is my thought on the ideal way for it to work, without any compromises like copying everything into a sequence and then performing the algorithm:

  • We would add an "initializing objects from open-ended dictionaries" too, roughly following the above JS algorithm.
  • We would modify the "add map elements from an iterable" to return a success/failure signal.
  • You'd use some sort of syntax (WebIDL gurus make this better, and see below for intended semantics)

    [Constructor(optional (Headers or MapInitIterable or OpenEndedDictionary) init)]

  • Your constructor algorithm would contain prose to the effect of:

    • "In the MapInitIterable case, [add map elements from iterable] init to this with adder method "append""
    • "In the OpenEndedDictionary case, [add map elements from open-ended dictionary] init to this with adder method "append".

    (you could use "set" for the latter instead of "append"; it doesn't matter.)

  • The intended semantics of the constructor definition are then that it tries in sequence: (1) if it's undefined, do nothing. Otherwise, (2) check for the Headers brand, and if present, use that; (3) if not, try the add map elements from iterable algorithm; (4) if that returns a failure signal, try the add map elements from open-ended dictionary algorithm; (5) if that returns a failure signal, throw a TypeError.

Note how there is no type argument to OpenEndedDictionary since calling this.append does the conversion at that stage.

Also note that in practice you could omit the Headers from the constructor since Headers is already iterable. It would be observably different in that if someone had instrumented Headers.prototype[Symbol.iterator] or Headers.prototype.append they would not get their instrumentation triggered in the brand-check case, I assume, since that assimilation would not happen through public APIs but instead by pulling the private state out of the other Headers instance and plopping it into this.

# bugzilla at jessica.w3.org (3 years ago)

www.w3.org/Bugs/Public/show_bug.cgi?id=27008

--- Comment #10 from Boris Zbarsky bzbarsky@mit.edu ---

[Constructor(optional (Headers or MapInitIterable or OpenEndedDictionary) init)]

The point of OpenEndedDictionary is to have something to do type coercions for you.

Here you apparently don't want them done, because you want to pass things as-is to the append method. So you don't actually want OpenEndedDictionary. You want something more like "object", except that's not distinguishable from sequence right now.

But given that you want all the behavior in prose anyway, apparently, sounds like you really just want to take "optional object" and then go from there.

# bugzilla at jessica.w3.org (2 years ago)

www.w3.org/Bugs/Public/show_bug.cgi?id=27008

--- Comment #11 from Cameron McCormack cam@mcc.id.au ---

I think as Boris says, given you want to pass the object down to either the "initialize map from an iterable" or "initialize map from an open-ended dictionary" prose algorithms, you don't gain anything from having syntax for MapInitIterable and OpenEndedDictionary. And given you can treat a Headers object like the from-iterable case, I think using optional object and passing the object off to a single prose algorithm that handles both initialization types would be the most straightforward thing to do. Call that algorithm "add map elements from an object" and have it do:

  • If object has an @@iterator, then call "add map elements from iterable".
  • Otherwise, call "add map elements from open-ended dictionary".

which is pretty much what the JS-to-union-value conversion algorithm would do when deciding whether we've got a MapInitIterable or OpenEndedDictionary.

If we need an API later where we do need to handle other IDL interface types differently (e.g. say if Headers weren't iterable), then we could make object be distinguishable from interface types. But for now I don't think it's necessary.

# bugzilla at jessica.w3.org (2 years ago)

www.w3.org/Bugs/Public/show_bug.cgi?id=27008

--- Comment #12 from Anne annevk@annevk.nl ---

I guess the construct I was thinking of would be something where we give enough information to IDL so it can create these instances by iterating over the provided value.

It seems IDL would only need to know the method name for that to be able to do the rest. This is assuming we do indeed want to do it via the method and allow JavaScript to overwrite what happens.

# bugzilla at jessica.w3.org (8 months ago)

www.w3.org/Bugs/Public/show_bug.cgi?id=27008

--- Comment #13 from Anne annevk@annevk.nl ---

So I guess my current opinion is that we should remove the construct Domenic added and fix bug 20158 instead. We want unrestricted dictionary / OpenEndedDictionary in IDL for numerous features and it makes little sense to use something else for Headers.

# bugzilla at jessica.w3.org (8 months ago)

www.w3.org/Bugs/Public/show_bug.cgi?id=27008

Tobie Langel tobie.langel@gmail.com changed:

       What    |Removed                     |Added

     Resolution|---                         |FIXED
         Status|NEW                         |RESOLVED

--- Comment #14 from Tobie Langel tobie.langel@gmail.com ---

Fixed by heycam/webidl/commit/1814384 and heycam/webidl/commit/a096dbc

Want more features?

Request early access to our private beta of readable email premium.