Bug 16075 - Make a float/double type that excludes NaN/Infinity/-Infinity
Summary: Make a float/double type that excludes NaN/Infinity/-Infinity
Alias: None
Product: WebAppsWG
Classification: Unclassified
Component: WebIDL (show other bugs)
Version: unspecified
Hardware: All All
: P2 normal
Target Milestone: ---
Assignee: Cameron McCormack
QA Contact: public-webapps-bugzilla
Depends on: 16331
  Show dependency treegraph
Reported: 2012-02-22 14:52 UTC by Aryeh Gregor
Modified: 2012-03-12 20:50 UTC (History)
7 users (show)

See Also:


Note You need to log in before you can comment on or make changes to this bug.
Description Aryeh Gregor 2012-02-22 14:52:52 UTC
float/double can be NaN/Infinity/-Infinity.  This is probably not desired by most if not all interfaces that use them.  The uses of float/double in HTML are the following, as far as I can tell, excluding readonly attributes and return types (since behavior there doesn't really matter):

* HTMLMediaElement and MediaController: .currentTime, .playbackRate, .defaultPlaybackRate, .volume
* TextTrackCue: constructor, .startTime and .endTime
* CanvasRenderingContext2D: scale(), rotate(), translate(), transform(), setTransform(), .globalAlpha, about a million others
* HTMLInputElement: .valueAsNumber
* HTMLProgressElement: .value, .max
* HTMLMeterElement: .value, .min, .max, .low, .high, .optimum

The CSS Transforms spec also currently uses doubles for CSSMatrix (see bug 15964), and SVG defines some interfaces like that as well (SVGPoint, SVGMatrix, etc.).

In all of these cases, as far as I can tell, NaN and infinite values are unlikely to be wanted.  Moreover, looking at a sampling of them, they seem to not define handling for those cases.  It is entirely unclear what should happen if you set a video element's .currentTime to NaN or Infinity, for instance, or if you try to scale() a canvas by a factor of NaN or Infinity.  The spec doesn't say.

I suggest that the IDL float and double types be defined to exclude NaN, Infinity, and -Infinity values.  Trying to convert such a value to float or double should raise a TypeError.  If there are any WebIDL users that actually want to allow such values, it should be via an extended attribute that lets them opt in.
Comment 1 Aryeh Gregor 2012-02-22 14:58:28 UTC
zewt suggests that they should be converted to +0, rather than raising a TypeError.  This matches the behavior of integer types, AFAICT, so it probably makes more sense.  (A priori, I'd have said throwing is more reasonable, but it's better to match integer types.)
Comment 2 Aryeh Gregor 2012-02-22 15:35:42 UTC
Ms2ger points out that HTML already defines that a NotSupportedError has to be thrown in these cases:


Except for canvas, where it's silently ignored:


The silent-ignore behavior for canvas needs to be supported somehow.  I definitely think the default handling of throwing an exception should be moved to WebIDL (and changed to TypeError for consistency).
Comment 3 Cameron McCormack 2012-03-05 00:47:09 UTC
I can see that it would be useful to distinguish between float/double values that take non-finite values and ones that don't in the IDL.  Rather than an extended attribute, I think it would be good to just have a separate type to distinguish them.

On the one hand, to me "float" and "double" really sound like the C types, where you can have NaNs and ±Infinity.  So removing those values by default from those types doesn't seem right.  Thus my first thought would be to have maybe "float" and "finite float" types.  OTOH, it's clear that not including those values is more common, so littering most uses of "float" with "finite" is maybe not the best solution.  If there is a succinct word we could place in front of "float" to mean "including the non-finite values" I can't think of it right now. :)

(Silently ignoring like on canvas calls could be done with an extended attribute or just by using the type that includes the non-finite values and defining the canvas operations to do nothing when those values are passed in.)

A crazy thought: define special types to represent NaN and ±Infinity and use union types when you want them:

  void f((float or NaN) x);
Comment 4 Anne 2012-03-05 07:24:31 UTC
"expanded float" / "inclusive float" / "infinity float"
Comment 5 Aryeh Gregor 2012-03-05 18:09:49 UTC
Do we know of any cases where specs actually want to allow NaN or +-Infinity?  If not, can we just not allow them at all for now?  Failing that, the union type suggestion sounds best -- it's ugly, but that's fine if there are no known uses.
Comment 6 Cameron McCormack 2012-03-06 01:45:27 UTC
I went with removing the non-finite values from float and double, and introducing two new types "unrestricted float" and "unrestricted double" which do have those values.  I noted these new types as being "at risk", in case we don't have any uses for them.  When passing non-finite values to an object expecting a float/double, a TypeError is thrown.  I haven't added an extended attribute for the "ignore the function call instead of throwing" for canvas; I think we can just have those the relevant functions take "unrestricted float"s and keep defining their special behaviour in those cases.


Let me know if this resolution is satisfactory, thanks.
Comment 7 Jonas Sicking 2012-03-06 02:50:29 UTC
Do we want to do the same thing with Date's? A javascript Date object can be an "invalid date". This happens for example for

x = new Date("foo");
Comment 8 Cameron McCormack 2012-03-06 03:00:36 UTC
(In reply to comment #7)
> Do we want to do the same thing with Date's? A javascript Date object can be an
> "invalid date". This happens for example for
> x = new Date("foo");

Possibly, although Dates are used far less often than floats/doubles so I'm not sure whether it's worth it at the moment.  There are only two uses of Date that are taken as input that I could find: HTMLInputElement.valueAsDate and Contact.birthday (from the Contacts API spec).  The former handles NaN dates specifically to do something other than throwing.  The latter doesn't say what it means for the birthday to be the invalid date value, but it also doesn't have much detail there.
Comment 9 Anne 2012-03-06 08:29:09 UTC
Wouldn't it be better to not throw for NaN / infinity so <canvas> does not need special casing? It seems nicer if people make a math mistake now and then to just let it slide and not do anything with the method. Maybe put a warning in the console or something.
Comment 10 Cameron McCormack 2012-03-06 23:28:31 UTC
I don't really like the pattern of ignoring a whole function call because one of the float/double arguments got a non-finite value.  It's trickier still when the operation is declared with a return type other than void -- you need to define what gets returned from it.

Maybe Aryeh's suggestion of mapping NaN/±Infinity to 0 would be OK, but I would like to see that we're all in favour of that change before making it.
Comment 11 Jonas Sicking 2012-03-07 02:25:09 UTC
I think having either of those behaviors as a default behavior for float seems very scary. It might make sense for some APIs, but very little for others.

I think we should make the default policy to throw, or just revert this whole bug and force specs to define behavior on a function by function basis.
Comment 12 Cameron McCormack 2012-03-07 02:34:43 UTC
Yes I tend agree with Jonas regarding throwing being better, but I think the introduction of the "unrestricted" varieties of float and double are useful and shouldn't be rolled back.  They give us common behaviour -- for cases that are very common -- without having to rely on all spec writers to specify it.