Bug 16725 - Treat omitted dictionary the same as empty dictionary
Treat omitted dictionary the same as empty dictionary
Status: RESOLVED FIXED
Product: WebAppsWG
Classification: Unclassified
Component: WebIDL
unspecified
PC All
: P2 normal
: ---
Assigned To: Cameron McCormack
public-webapps-bugzilla
:
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2012-04-13 11:46 UTC by Simon Pieters
Modified: 2013-10-23 18:31 UTC (History)
8 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Simon Pieters 2012-04-13 11:46:57 UTC
Consider new A() with

[Constructor(optional B b)]
interface A { };
dictionary B { DOMString foo = "bar"; };

WebIDL should say that an omitted dictionary argument is equivalent to a specified empty dictionary, to not require all specs that use optional dictionary arguments to say so in prose.

Also "the value the dictionary member is to be considered to have when not present" is pretty vague language and should be tightened up with something clear and containing some normative keyword...
Comment 1 Cameron McCormack 2012-04-14 03:34:12 UTC
I agree it would be good not to have to write things like

  1. Let dict be b if it were specified, or an empty dictionary of type B
     otherwise.
  2. Do something with the "foo" member of dict.

but I'm not sure what to use instead.  I think it might be a bit confusing to allow

  1. Do something with the "foo" member of b.

if b weren't specified at all.  I guess you're suggesting that it's like there's a default { } value for the optional argument, but have dictionary types get a default value automatically seems inconsistent with other types.  What about an explicit

  [Constructor(optional B b = { })]
  interface A { };

?  Might be too much visual noise for what's probably going to be a very common case.  Let me know if you have any more concrete suggestions.

> Also "the value the dictionary member is to be considered to have when not
> present" is pretty vague language and should be tightened up with something
> clear and containing some normative keyword...

I guess it's vague, but it's just stating the meaning of "default value".  Later on there is wording that says the bit after the "=" gives the default value and how the actual tokens are considered as IDL values.  What more do you think needs saying?
Comment 2 Simon Pieters 2012-04-16 05:35:31 UTC
I'm fine with either of those.
Comment 3 Jonas Sicking 2012-04-25 07:17:43 UTC
If we want this to be consistent across all APIs where dictionaries are used, then I don't think requiring |optional X x = {}| is a good option since people will forget to put it in the API.

Given that dictionaries always describe what is essentially a collection of optional arguments, are there really cases when a dictionary member will be non-optional?
Comment 4 Tab Atkins Jr. 2012-04-26 01:05:07 UTC
(In reply to comment #3)
> Given that dictionaries always describe what is essentially a collection of
> optional arguments, are there really cases when a dictionary member will be
> non-optional?

Yes.  In languages with *proper* keyword-arg support, keywords args are also sometimes used simply to make some of their arguments more comprehensible.  

For example, a db library I wrote for myself several years back took some connection arguments in its constructor.  You were required to pass the db name, but the username and password were optional.  All of them were keyword arguments, though, to make it clearer in reading.

That said, this definitely seems to be a minority case.  In most cases I expect that the dict will be just optional arguments, and so omitting it would be acceptable.

Plus, if you *require* a dictionary, it's almost certainly not the mere presence of the dictionary you need, but rather the presence of certain members (and perhaps those members with certain values).  You'd need to test for this in the prose anyway so you can throw an exception, so it doesn't seem valuable to just make the mere absence of a dictionary throw by default.

So, I support this change.
Comment 5 Jonas Sicking 2012-04-26 10:16:49 UTC
Indeed. I would even go so far as to say that it won't be rare to use dictionaries for required arguments (though the common case will likely be for optional ones).

But like you say, in those cases the dictionary itself isn't the required part, but rather the dictionary plus one or more properties.

This can be described in prose right now by doing something like:

dictionary MyDict { boolean prop; };
someFunc(MyDict);

and say that if the "prop" argument is not defined an exception is thrown. Maybe down the line we can add syntax for required dictionary arguments but I feel like that is premature at this point.

So yeah, I think dictionary arguments should always be optional as far as the IDL goes, and default to an empty dictionary. And passing undefined (and maybe null) should result in the same behavior as an empty dictionary.
Comment 6 Jonas Sicking 2012-05-07 05:13:10 UTC
One possible solution is to make it a WebIDL error to have a dictionary argument which isn't explicitly marked as optional.

That way we don't need a special rule which says that dictionaries are optional even if they are not explicitly marked as such, which I agree would be a bit confusing when reading the IDL.
Comment 7 Cameron McCormack 2012-06-25 02:06:26 UTC
What about for dictionaries that appear in the middle of an argument list?

  void f(long x, MyDict y, long z);

This one can't be optional, because of the rule that optional arguments must be trailing.  Could we allow non-optional dictionaries if the following argument is non-optional, but if the argument is at the end of the argument list or followed by an optional argument, it must be optional?
Comment 8 Cameron McCormack 2012-06-25 05:02:33 UTC
OK, I have done this:

* dictionary type arguments that are followed by another optional argument,
  or which are at the end of the argument list, must be specified as optional,
  explicitly
* optional dictionary type arguments are treated as having default values
  implicitly
* nullable types can no longer use a dictionary type as its inner type
* null and undefined get treated as an empty dictionary when being converted
  to an IDL dictionary value
* dictionary types are no longer distinguishable from other nullable types

http://dev.w3.org/cvsweb/2006/webapi/WebIDL/Overview.xml.diff?r1=1.552;r2=1.553;f=h
Comment 9 Boris Zbarsky 2012-06-26 17:23:52 UTC
Any chance of signing up for some way to be notified of spec changes like this?
Comment 10 Cameron McCormack 2012-06-27 00:09:17 UTC
(In reply to comment #9)
> Any chance of signing up for some way to be notified of spec changes like this?

There's https://lists.w3.org/Archives/Member/member-webapi-cvs/ if you have Member access, which has notifications of every checkin under http://dev.w3.org/2006/webapi/.  I don't think there's another mechanism to be notified of every change to the spec currently.
Comment 11 Olli Pettay 2013-10-22 21:58:23 UTC
(In reply to Cameron McCormack from comment #8)
> * dictionary type arguments that are followed by another optional argument,
>   or which are at the end of the argument list, must be specified as
> optional,
>   explicitly
I don't understand this.
Now you can't have a method which requires caller to pass some dictionary.
Or you can, but you need to add some artificial non-optional non-dictionary
param after the dictionary.
Comment 12 Cameron McCormack 2013-10-23 05:32:43 UTC
(In reply to Olli Pettay from comment #11)
> I don't understand this.
> Now you can't have a method which requires caller to pass some dictionary.
> Or you can, but you need to add some artificial non-optional non-dictionary
> param after the dictionary.

That was by design.  Given the way that dictionaries are used, it seemed like a good idea to require them to be optional so that authors could always omit it.  Do you need to have the dictionary argument be non-optional because otherwise it would e.g. interact with the rules for overloading, and you wouldn't be able to write the API you want?  Or do you disagree with encouraging this kind of API pattern?
Comment 13 Olli Pettay 2013-10-23 12:15:04 UTC
I agree encouraging to that API pattern is good, but it is odd limitation
that one can't force that API user actually needs to pass some sane
value.
There can be cases when there are no sane defaults.
Comment 14 Anne 2013-10-23 12:25:22 UTC
Maybe at some point we can add required dictionary members at which point the dictionary would be implicitly required as well. But for now we do not have that.
Comment 15 Domenic Denicola 2013-10-23 13:31:34 UTC
> Maybe at some point we can add required dictionary members at which point the dictionary would be implicitly required as well. But for now we do not have that.

This makes a great deal of sense to me, +1. In the meantime though, I do not know what the best behavior is to express these ideal semantics in terms of what current WebIDL allows.
Comment 16 Jonas Sicking 2013-10-23 18:31:18 UTC
The implementation of an API can always check that a dictionary argument was passed. I.e. we can always use prose to say that a function throws unless a particular dictionary argument was passed.

Might not be possible to differentiate passed-undefined from did-not-pass, but that is probably fine.