BREAKING: Convert the `unrestricted` keyword into an extended attribute by ExE-Boss · Pull Request #857 · whatwg/webidl
Very well put @yuki3.
First, I think it's worth separating primitives from all other types, for this discussion. I am reasonably happy with our non-primitive type system, e.g. dictionaries, enums, callbacks, sequences, records, promises, etc. So I think this is mostly about primitives. In particular: numeric types, boolean, DOMString, ByteString, USVString, symbol, and maybe any and object.
(Edited to add: I guess enums are a kind of string type, if you think about it. Hmm!)
Of those, numeric types and string types are basically what we're discussing. The rest are straightforward mappings to JS primitives.
One potential framework we could work toward is saying that types should correspond to JavaScript types, and extended attributes should modify the conversion algorithms. This would argue for turning all numeric types into a single type. This would have a benefit of corresponding IDL better to JS-ecosystem things like TypeScript or MDN documentation. However, for numeric types especially, this is more cumbersome for spec authors and implementers.
Another potential framework is to try to match some sort of consensus-type-system of C++/Rust, i.e. implementer languages. This is fuzzier, both because of differences between C++ and Rust, and because of differences in C++ dialects (e.g. different string types). For numeric types, I think the result would be similar to #843. For strings, its unclear which direction this would lean.
One issue with a C++/Rust type approach is that those languages don't have an idiomatic type for "double/float but not Infinity or NaN", and it's currently an explicit goal of Web IDL to make the easy path for spec authors not require thinking about those. That is, unrestricted behavior is opt-in in Web IDL, both currently and with this PR. Whereas if we took a principled C++/Rust approach, it would be opt-out.
A third possibility would be something in between. For example, we could try to be "JS first", but add conveniences or concessions to make spec-writing easier. It's super-common to want to accept only nonnegative integers, so forcing people to write [EnforceRange] [NonNegative] [Integer] number or something like that is not great. It's also historically common to add C++-like wrapping behavior for numbers by using unsigned long or long, even if this is not great practice. Maybe we just make some typedefs for the common cases, e.g. uint64 and int32, but we get rid of the rarer cases (like octet or byte or short), requiring those to be written long-hand or typedefed in the using spec.
(As an aside, people may enjoy my 2014-era proposal in #33 for reforming the numeric types. I don't really like it any more, but it illustrates somewhat similar thinking, of trying to be "JavaScript first" and not treating C++ boundaries like 232 or 0 as special. #33 (comment) is a 2019-era update on my thinking to be more spec-author friendly, but it is definitely not prinicipled in the way @yuki3 describes.)