Notes from Monday's meeting with TC39 folks

On Monday, Brendan, Allen, Mark, Jonas had a second ad hoc meeting to
discuss Web IDL.  Below are some rambling notes.


I didn’t agree with the part of Allen’s analysis of overloading that
claimed that it currently requires expensive overload resolution
whenever a function is called (the implementation should know ahead of
time exactly what set of ES types correspond to which overloaded
operation).  There was agreement though about the “impedence mismatch” 
when considering ES as the most important language binding, and using
union types seemed like a plausible way of doing this.  Specs currently
tend to consider them in prose as the same operation/function anyway.

Moving to union types would help discourage certain poor designs, such
as canvas’ createImageData(), where certain arguments change their
meaning depending on how many are passed.  If we restrict ourselves to
union types plus the current way of specifying optional arguments, then
it does make some patterns more difficult to specify.  In particular, if
with the current overload mechanism we had

  void f(in DOMString s);
  void f(in DOMString s, in float x, in float y);
  void f(in Element e);
  void f(in Element e, in float x, in float y);

then we’d need need to write this as

  void f(in DOMString | Element a,
         in optional float x,
         in optional float y);

thus allowing two arguments to be passed, if you just look at the IDL,
and then prose would be required to disallow the two argument call.  We
could go back to the way [Optional] used to be specified, which meant
that that argument and all following could be omitted, but I found that
to be a bit unclear.  (Currently, overloading is required in the spec to
handle this case.)

Another thing I just noticed is that it doesn’t allow you to specialise
the return type depending on which overload is invoked.  I can’t
remember seeing any web API that currently has different return types on
overloaded operations.


With this union types model, Null would become a built-in type in the
IDL.  As in the current spec, the string type (DOMString; maybe we can
reconsider renaming it again) would not have null as one of its values.
A union type would be needed to allow null as a distinct value, e.g.:

  attribute (DOMString | Null) x;

and the ‘?’ suffix currently used to denote a nullable type could be
syntactic sugar for that:

  attribute DOMString? x;

(And of course typedefs could be used to make union types more usable.)

We talked about having an Undefined type in the IDL, too, but I’m not
sure whether we came to an agreement on that.  If we did have it, then
we should distinguish the case where the Undefined type is accepted as
an argument value with the case where the argument is omitted.

The thought is that there are few APIs where it makes sense to
distinguish null and "" when accepting a DOMString (getAttribute being a
notable one).  But we will need to check.  There are two possibilities
on how ES values are coerced to DOMString by default:

  A) null is converted to ""
     anything else is converted using the String constructor

  B) everything is converted using the String constructor

If an analysis shows that the former covers most cases (majority?
plurality?) then we would go with that and also not allow overriding
this in the IDL as you can do with [Null] (or [TreatNullAs], as it
became).

With regards to how the undefined value should be coerced to a string,
Jonas said (paraphrasing):

  A lot of people have argued that we should always use the String
  constructor so undefined gets converted to "undefined" (and similarly
  for null).  I see logic in that too.  What makes the least amount of
  sense is what we do in Gecko, where null comes "" and undefined
  becomes "undefined".  I think we should recommend converting both to
  the empty string and seeing what people say.  We can use union types
  to handled undefined differently if necessary.  I think IE generally
  stringifies both null and undefined.

And Mark said:

  We shouldn’t be considering converting null to "" but undefined to
  "undefined".


Later discussion, assuming that there was no Undefined type in the IDL,
suggested that the Null IDL type could be specified as either null or
undefined in ES, but when returned from the implementation to ES would
always be denoted using null.


We also discussed removing the null value from interface types, which
would require IDL writers then to use union types to explicitly allow
null.  For example:

  attribute Node? firstChild;   /* or (Node | Null) */
  void appendChild(in Node n);

where firstChild can be null, but the value passed to appendChild
cannot.  We’d define a TypeError (or something) to be thrown if null was
passed to appendChild here.


Due to trouble with catchalls clashing with properties that exist on an
object, we agreed that new APIs shouldn’t (mustn’t?) use these.  Name
getters would need to remain in the spec to handle current APIs that use
them, such as localStorage.  We would change them back to extended
attributes ([NameGetter] and so on) since they wouldn’t be part of the
IDL language proper.  Similarly for callers, which seem to be an anti-
pattern.


We came up with five (or four) categories for Web IDL features to be
classified as being members of, in order to manage functionality that we
don’t want to perpetuate:

  1. Web IDL “the good parts”
    Features that aren’t controversial.  Mark wanted to ensure that this
    set of features was implementable in ES5 strict code.  Brendan
    thought that array-like objects (i.e., the use of index getters)
    should fall in this category too, even though it is not possible to
    write array-like objects in ES5 currently.

  2. De jure parts of the spec required for legacy support
    This would include catchalls (i.e., name getters).  New APIs must
    not use features in this set, but must implement them as specified.

  3. “Deprecated”
    Same as category 2, but that it’s expected that the features could
    be removed from the platform (and Web IDL) at some point in the
    future.  (This category might be empty, and might as well be removed
    since they can just be category 2 features that are removed in a
    future revision of the spec.)

  4. Something like ES5’s Appendix B
    Not normative.  These would be advisory notes about things
    implementations might want to do for compatibility, but it would be
    up to the implementor to determine whether it was required.  If
    deemed required, then the implementor would follow the definitions
    in this section (that is, it’s defined how to do it, but optional
    whether it is required).  document.all falsey-ness was considered
    to be in this category, although currently that behaviour is
    specified in HTML5, not by virtue of any Web IDL feature.

  5. Things considered for standardisation but rejected, and why
    Also not normative, and requirements wouldn’t be listed at all.
    (Not sure if any features were deemed to be in this category.)


Mark wondered whether there should be both [Supplemental] and the
‘implements’ statement, since both effectively augment the type being
supplemented (or the type on the LHS of the ‘implements’), and might
cause the same changes to an interface’s prototype object (under a
certain design of flattening multiple inheritance to single inheritance
prototype chains).

I had some issues with [Supplemental] effectively allowing an interface
to lose members depending on which set of specs you consider when
generating a Java interface, which would cause binary compatibility
problems.  (You want to only allow methods to be added to an interface.)
In Java you handle these cases with mixin interfaces, as is currently
done with various DOM specs (e.g. DocumentCSS, DocumentView).  I think
it might be better to allow these to have unique interface names, like
DocumentCSS, but with an extended attribute that indicates explicitly
what prototype object is being supplemented with new properties — maybe:

  [Supplemental]
  Document implements DocumentCSS;

or so.


Those of us who were able to stay until the end of the meeting (all but
Allen) were happy with a few initial recommendations, but I
unfortunately don’t have a note of them.  I believe they included:

  * Not allowing callable objects in future APIs
  * Not allowing inheritance DAGs (only trees)

and possibly also not allowing catchalls in future APIs, but I still
need slightly more convincing for that; despite problems of clashing
namespaces, it seems like a handy pattern for script authors.


Those who attended: please chime in with clarifications/corrections.


Thanks,

Cameron

[1] http://en.wikipedia.org/wiki/LOTE

-- 
Cameron McCormack ≝ http://mcc.id.au/

Received on Thursday, 8 October 2009 04:58:31 UTC