Bug 11451 - Add a string enum type
Summary: Add a string enum type
Status: RESOLVED FIXED
Alias: None
Product: WebAppsWG
Classification: Unclassified
Component: WebIDL (show other bugs)
Version: unspecified
Hardware: All All
: P3 enhancement
Target Milestone: ---
Assignee: Cameron McCormack
QA Contact: public-webapps-bugzilla
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2010-12-01 21:39 UTC by Cameron McCormack
Modified: 2011-12-21 08:41 UTC (History)
7 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Comment 1 Anne 2010-12-01 22:00:10 UTC
This might also be useful for IDL attributes in HTML5 that are limited to known values.
Comment 2 Jonas Sicking 2010-12-01 22:19:30 UTC
What is the proposal here? Wouldn't allowing something like:

interface XMLHttpRequest {
  ...
  const DOMString REQUESTTYPE_FOO = "foo";
  ...
};

sort of defeat the purpose since people are bound to get into cargo-cult copying of code like:

xhr.requestType = XMLHttpRequest.REQUESTTYPE_FOO;

as well as rat-hole discussions about if best practice is to do the above or to use the sting "foo" directly.


Or is the proposal here something wholly different and I'm totally misunderstanding things?
Comment 3 Cameron McCormack 2010-12-01 22:31:28 UTC
I think the proposal is for something like:

  stringenum CanPlayTypeValue = { "", "maybe", "probably" };

  interface HTMLMediaElement : ... {
    CanPlayTypeValue canPlayType(in DOMString type);
    ...
  };
Comment 4 Anne 2010-12-02 09:23:47 UTC
Indeed. For the HTML5 case -- if we want to address it with this -- an ASCII case-insensitive matching flag is needed.
Comment 5 Cameron McCormack 2011-05-23 02:52:53 UTC
Going to punt on this to v2.
Comment 6 Anne 2011-09-17 07:47:46 UTC
This would also be great for XMLHttpRequest.responseType. Web IDL could also handle ignoring values that are not part of the enum.
Comment 7 Dominique Hazael-Massieux 2011-11-24 15:56:30 UTC
*** Bug 14843 has been marked as a duplicate of this bug. ***
Comment 8 Cameron McCormack 2011-12-06 05:25:49 UTC
Given we're encouraging the use of strings instead of integer constants, it probably makes sense to add this and not punt on it.

I'm not sure about ignoring unrecognised values.  Wouldn't it be better to throw?
Comment 9 Anne 2011-12-06 10:07:17 UTC
We do not throw currently (e.g. <canvas> 2D API, XMLHttpRequest responseType) and it allows for pretty easy feature testing.

E.g. obj.responseType = "json"; if(obj.responseType == "json") support!
Comment 10 Anne 2011-12-06 10:10:42 UTC
I think for http://dvcs.w3.org/hg/xhr/raw-file/tip/Overview.html#the-responsetype-attribute we should have move step 3 (checking of values) to the front. And then when we have native Web IDL support that step can be removed. At least, I hope they can be defined something like that.
Comment 11 Travis Leithead [MSFT] 2011-12-06 18:25:42 UTC
One of the benefits of string (enum types) is that it's easily extensible, both for future needs (like adding "stream" as a responseType) as well as vender-specific extensions if needed.

Throwing on unrecognized values could limit their value in my opinion.
Comment 12 Cameron McCormack 2011-12-09 00:12:01 UTC
What should happen when passing an invalid string enum value to an operation?

  enum A { "x", "y" };
  interface B {
    void f(A a);
  };

  getB().f("z");

Doing nothing in f seems wrong.  Should we allow the invalid value to be passed through, and require specs to define their behaviour for operations that take invalid string enum values?
Comment 13 Anne 2011-12-09 10:21:26 UTC
For that e.g. <canvas>' createPattern() throws. I do not recall any other such API at the moment but throwing in that case makes sense to me.
Comment 14 Travis Leithead [MSFT] 2011-12-09 18:59:23 UTC
I suppose that if you throw in the case of unrecognized values, then that's one way to feature-detect that you're running in a UA that doesn't support some new value of the enum.

On the other hand, won't you be able to inspect the enum's values programmatically to ensure the string you want will be supported? In other words, given:

enum A { "x", "y" };

Is "A" exposed to JavaScript along with its values?
Comment 15 Tab Atkins Jr. 2011-12-09 19:15:51 UTC
(In reply to comment #14)
> I suppose that if you throw in the case of unrecognized values, then that's one
> way to feature-detect that you're running in a UA that doesn't support some new
> value of the enum.
> 
> On the other hand, won't you be able to inspect the enum's values
> programmatically to ensure the string you want will be supported? In other
> words, given:
> 
> enum A { "x", "y" };
> 
> Is "A" exposed to JavaScript along with its values?

Some recent APIs that take dictionaries define the dict as an interface that you can poke at to find support.  It would be nice to have the same with enums.
Comment 16 Anne 2011-12-10 13:40:24 UTC
I was only suggesting we throw for methods. We should not throw for attributes. And I'm not sure what the best way to support enum is. It might be nicer if we could just do:

attribute "foo" "bar" "baz" someAttribute;

Tab, example of such an API?
Comment 17 Tab Atkins Jr. 2011-12-14 19:26:21 UTC
(In reply to comment #16)
> I was only suggesting we throw for methods. We should not throw for attributes.
> And I'm not sure what the best way to support enum is. It might be nicer if we
> could just do:
> 
> attribute "foo" "bar" "baz" someAttribute;
> 
> Tab, example of such an API?

The MutationObserver API, for instance, defines a MutationObserverOptions interface, which it uses to type the second argument to observe().
Comment 18 Anne 2011-12-14 19:42:06 UTC
This is getting off-topic, but we changed that, fwiw.
Comment 19 Tab Atkins Jr. 2011-12-14 20:19:59 UTC
(In reply to comment #18)
> This is getting off-topic, but we changed that, fwiw.

You just mean that it was renamed to MutationObserverInit, right?  According to DOM4 tip it still defines an interface for the options object.
Comment 20 Cameron McCormack 2011-12-20 23:35:47 UTC
I wasn't planning on exposing the enum in any way.  If we make unknown string values assigned to attributes be ignored, that can be used to feature detect.  Similarly for catching an exception if that's how we make operations handle unknown values.

(In reply to comment #15)
> Some recent APIs that take dictionaries define the dict as an interface that
> you can poke at to find support.  It would be nice to have the same with enums.

Not sure what you mean by defining a dictionary as an interface.  Do you mean like `[Callback] interface SomeOptions { ... }`, the style used before dictionaries were introduced?
Comment 21 Tab Atkins Jr. 2011-12-20 23:50:33 UTC
(In reply to comment #20)
> I wasn't planning on exposing the enum in any way.  If we make unknown string
> values assigned to attributes be ignored, that can be used to feature detect. 
> Similarly for catching an exception if that's how we make operations handle
> unknown values.
> 
> (In reply to comment #15)
> > Some recent APIs that take dictionaries define the dict as an interface that
> > you can poke at to find support.  It would be nice to have the same with enums.
> 
> Not sure what you mean by defining a dictionary as an interface.  Do you mean
> like `[Callback] interface SomeOptions { ... }`, the style used before
> dictionaries were introduced?

Yes, that's what I'm referring to.

I still think it can be good to expose them somehow, as checking for undefined on an object somewhere is easier than checking the value after every set, or catching an exception on every set.

What'll actually happen, if they're not exposed for easy testing, is that people will just use Modernizr (or some hand-rolled equivalent) to test for the values they need, store the results in an object, and then use that object for easy testing.  I don't see a good reason to require this when it can be done for them.
Comment 22 Cameron McCormack 2011-12-21 00:05:28 UTC
Are you asking for window.EnumName to exist, or for window.EnumName to exist and there be a way to get the list of strings the implementation supports for it?

If we were going to expose it, then I guess something equivalent to the following?

  window.CanPlayTypeValue = ["", "maybe", "probably"];
Comment 23 Tab Atkins Jr. 2011-12-21 00:14:37 UTC
(In reply to comment #22)
> Are you asking for window.EnumName to exist, or for window.EnumName to exist
> and there be a way to get the list of strings the implementation supports for
> it?
> 
> If we were going to expose it, then I guess something equivalent to the
> following?
> 
>   window.CanPlayTypeValue = ["", "maybe", "probably"];

The latter, though probably more something like:

window.CanPlayTypeValue = {"":true, "maybe":true, "probably":true}

This way, one can do a simple test like "if(window.CanPlayTypeValue['probably']){...}".

Dictionaries would be exposed in the same way, with the object holding the keys they support.
Comment 24 Cameron McCormack 2011-12-21 00:17:19 UTC
One thing that worries me a little about this kind of feature detection is that the existence of these properties (and it's just the same with consts) does not necessarily mean that the values are accepted on any particular attribute or operation.
Comment 25 Tab Atkins Jr. 2011-12-21 00:21:43 UTC
(In reply to comment #24)
> One thing that worries me a little about this kind of feature detection is that
> the existence of these properties (and it's just the same with consts) does not
> necessarily mean that the values are accepted on any particular attribute or
> operation.

Yes, one must be aware of how the API works.  That's true without such a listing, though.  This doesn't change the way that anything is done, or provide new abilities, or anything like that.  It just simplifies the check for whether something is supported or not.  Rather than reading the value after setting it, or catching an exception, there's a property existence check.  This check is used in the exact same way as the prior two types of checks, it's just easier to use.

In other words, your worry is unrelated to my request itself, but rather concerns itself with the very nature of feature testing.
Comment 26 Cameron McCormack 2011-12-21 00:24:32 UTC
I don't think the two are equivalent, especially when you have more than one attribute/operation that uses the enum.  By assigning the string to the property corresponding to the attribute, and checking its value afterwards, you have a much stronger idea of whether that attribute supports that value than by seeing if the enum object has the property on it.  Now, it is likely that if the property exists on the enum object that it is supported on at least one attribute/operation, but it won't help you tell which.
Comment 27 Cameron McCormack 2011-12-21 01:45:54 UTC
I've added string enumerations to the spec, performing exact case matching, ignoring invalid values when assigned to attributes and throwing in other cases.  I haven't exposed them on the global object.

http://dev.w3.org/cvsweb/2006/webapi/WebIDL/Overview.xml.diff?r1=1.428;r2=1.430;f=h
Comment 28 Simon Pieters 2011-12-21 08:41:03 UTC
FTR I agree with heycam, we should prefer feature testing on the object you want to use. Exposing the enum and its values on the global object for "easier" testing smells a bit like hasFeature(), and seems unlikely to be reliable in practice.