(accidentally left out es-discuss when I responded to Norbert… response if below)
On Monday, 3 September 2012 at 13:20, Marcos Caceres wrote: > Hi Norbert, > > On Saturday, 1 September 2012 at 00:31, Norbert Lindenberg wrote: > > > On Aug 31, 2012, at 7:17 , Marcos Caceres wrote: > > > > The way I understand it, backwards compatibility means that code that runs > > on an old version without exceptions continues to run on the new version > > with the same results. It does not mean that code that takes advantage of > > new capabilities in the new version will get the same results on the old > > version. > > You are correct, lets call this graceful degradation or fault tolerance. I > guess it does not matter what we call it, so long as it's understood that > desired behaviour is that the API continues to work on old runtimes when if > new options are made available without significant code changes (such as > wrapping code in try/catch blocks). > > > Bogus hypothetical example - ES i18n.next introduces "formal", where the > > > day always has the first letter capitalised: > > > > > > {day: "formal"} > > > > > > Let's assume weekday - the day property currently has only "numeric" and > > "2-digit", therefore no letters. > > > > > Because of this throw behaviour, the introduction of "formal" in a future > > > spec would potentially break all existing implementations today. If this > > > behaviour is left as is, (1) all calls to the i18n API will need to be > > > wrapped in try/catch (as a preemptive measure as the introductions of a > > > new option value would cause a throw). As a side effect, (2) users on old > > > browsers could be negatively impacted in the future without the knowledge > > > of the developer. > > > > > > Applications only have to wrap their calls in try/catch if they use a new > > option value and want to run on old browsers that may not understand the > > new value. > > The problem with the above is that the developer may not even know that the > API throws - if the developer runs their code on only browsers that support > "formal" then she would never know there was a problem. The above also > assumes the code is being maintained by the developer. The developer may > choose not to care about particular users or may not have access to (or even > be aware of) their application failing on particular browsers. > > As I've stated before, the current API design is allowing developers to > unknowingly exclude users. By simply providing a fallback, this problem goes > away. > > It's similar to how they have to check whether new API exists if they want > > to run on browsers that may not have that API yet. > > > > I don't think the API design should rely on workarounds that have emerged to > overcome issues with the Web platform (i.e., feature testing and duck typing > are in many ways a failing of the platform, and not something that should be > built on, IMHO). APIs should not rely on having to be wrapped in support > checking code as it makes code much more inefficient, harder to read, and > less maintainable. Compare: > > //always gonna get something the user understands… > var ldate = (new Date()).toLocaleString("en", {day: "formal"}); > > To: > if(window.Intl !== undefined){ > try{ > var ldate = (new Date()).toLocaleString("en", {day: "formal"}); > }catch(e){ > //ok, gotta try something else… > ... > } > } > > Also, feature detection is usually done at the most basic level: like > window.hasOwnProperty("Intl"); and not try/catch every possible option in the > an API. Take a look at Modernizr: > > http://modernizr.com/downloads/modernizr.js > > Most tests are pretty simple (in a good way): in as far as they most just > test "if (x in y) return true/false". In most cases, actual functionality is > not tested - just presence of a given host object, method, or attribute. > > Applications probably also would not have to wrap all calls - I think > > modern applications run a sequence of tests early on to detect which of the > > features they want to use are supported, and then adjust their behavior > > accordingly (polyfill, dumb down, ask the user to upgrade, ...). > > > > This assumes a lot of sophistication on the part of developers. History shows > that most developers don't do unit testing or any other kind of testing. > > The API should make no assumptions about the code around it - the assumed > context should not matter (i.e., wrapped in try/catch or not should not > factor into the API design). To be clear: the API should be designed to be > testable, but it should be assumed that it will *not* be tested. > > In this specific case, checking whether "formal" is supported also lets > > applications decide what to do if "formal" is not supported. > > > > This assumes that runtimes are the same across platforms or that the > developer has access to all the platforms on which she is required to test. > > Most likely, it would choose "long" instead because it's closer to "formal" > > than "numeric", which would be the default used by the implementation. > > > > The choice of value is not really important here. What is important is that > the API continue to return something useful to the user irrespective of the > developer's fumble. > > > For the case of (1), developers may not even be aware that the API throws > > > (or has thrown) for a particular set of users using an outdated browser - > > > I personally found that it throws by accident. This would lead to (2), > > > which unfairly punishes users without the developer's knowledge - causing > > > the application to potentially stop working all together if the exception > > > is not caught. > > > > > > > > > > Web developers generally need to be aware that there are different browser > > versions with different capabilities - that's not new. They decide whether > > IE 6 is the baseline or IE 9, and then check for features that were > > introduced after the baseline version. > > That's simply impossible to do in most cases and puts a massive financial and > technological burden on developers: imagine you had to own a copy of Windows > XP, Vista, 7, and Windows 8… as well as then have a Mac and a machine to test > Linux, as well as a range of iOS devices, Android Devices, Windows Phone 7 > and 8, a Blackberry, etc. etc. The number of browser engines and environments > that ES is being used on continues to grow, this task simply becomes > impossible - which is also why I argue that the API needs to be more fault > tolerant. > > The above also assumes that the software is being maintained: what happens if > the developer adds "formal" then stops maintaining the software, but it's > still used by people? > > This is also compounded by the fact that release cycles are changing - it is > impossible to test every possible version of Chrome and FireFox since they > started their rapid release cycle… To make matters worst, if a particular > browser vendor decides tomorrow to abandon support for Windows XP, that > potentially leaves millions of people out in the cold… I don't think IE10 > will be supported by XP. Fast-forward 5-10 years, Windows 8 becomes the new > Windows XP - and IE10 will be the new "IE6" with millions stuck on that > version. > > And from a user's perspective, those who can't afford latest and greatest > software (or who has no option to update their browsers, like in iOS) risk > being deliberately or accidentally excluded by developers. > > Also, setting a baseline sets a bad practice (and is fundamentally against > the core principles of "one Web"): developers should never target a > particular baseline - they unfortunately have to do this sometimes, but it's > certainly not something that should be assumed in the design of an API. > > > > IMHO, falling back to defaults, or by ignoring bogus values, would make > > > the API degrade gracefully without negatively impacting users (that is > > > something I really like about the API today - it does that if you feed it > > > bogus language tag or bogus option it does not understand). I think it > > > should be the same for option values. > > > > > I would also argue that having the above throw is inconsistent with the > > > rest of the API. The API already provides nice fallbacks to defaults in > > > most cases. For example, today (without i18n API support), calling any of > > > the to*LocaleString() simply "just works" - overcoming side-effect 2 > > > above and not punishing users with an exception. I think most developers > > > would expect that kind of fallback behaviour - you are guaranteed to get > > > a date/time/number that the user will understand (even if it's not as > > > pretty as a custom formatted one): > > > > > > x.toLocaleTimeString("en", {foo: "bar"}) > > > //"12:00:00 AM" > > > > > > x.toLocaleTimeString("klingon", {foo: "bar"}) > > > > > > //"12:00:00 AM" > > > > > > …and so on… which is a great graceful fallback behaviour . > > > > > > Yes and no. For structurally invalid language tags, it will throw. For > > structurally valid tags that it just doesn't recognize, it will use > > fallbacks. And there has been a lot of discussion about these fallbacks > > between some internationalizers who want a lot of flexibility to do what > > they think is best for the user, and TC 39 members who want behavior fully > > specified so that it's predictable and consistent across implementations. > > I personally think the behaviour of the API with regards to language tags is > reasonable because it checks language-tag structure, but does not throw when > the browser does not know the language: i.e., it behaves in a future proof > manner that degrades gracefully. This is exactly how I think the options > should work too for unknown options: so long as the option is a String, it > should behave the same way as with language tags - i.e., fall back to > something gracefully when the value is unknown. > > > If the spec authors want to "warn" developers that they've used an > > > unsupported option value, maybe put into the spec to call > > > "console.warn()" or similar, if available. That allows developers to know > > > they've used something unsupported/unknown/or misspelled without > > > punishing users - mobile safari and Chrome do this already for > > > meta-viewport values, so there is some helpful precedence here. Yes, > > > relying on "console.warn" is non standard, but this could just be > > > specified as non-normative text by just saying where appropriate in the > > > spec: > > > > > > "Optionally, warn the developer that the option value is unsupported by, > > > for example, calling console.warn() or similar if available to the > > > implementation." > > > > > > I think all modern browsers support the console object, and so does > > > Node.js. > > > > > > ECMAScript is used in more environments than just browsers and Node.js, and > > TC 39 is generally staying away from making any specific requirements on > > the host environments. Clause 16 of the Language spec specifies precisely > > which errors must be reported when, but says nothing about how to report > > them. > > That's fine, but my argument is really about not forcing developer errors > onto users (users can't do anything about those problems). It's simple to > specify a fallback in the spec that protects users from developer error (and > makes developers lives easier because they can feel confident that the API > will always return something the user is likely to understand - as it does > today). > > > On the other hand, if the developer wants to check if what they inputed > > > as options is supported by the API, they can call .resolvedOptions() and > > > manually verify that all their options were understood by the browser. So: > > > > > > var formatter = new v8Intl.DateTimeFormat(x, {day: "formal"}), > > > options = formatter.resolvedOptions(); > > > > > > if(options.day !== "formal"){ > > > //no formal support, need to use something else > > > options.day = "long"; > > > formatter = new v8Intl.DateTimeFormat(x, options), > > > } > > > … continue… > > > > > > > > > > > > Actually, options.day !== "formal" does not mean that the implementation > > doesn't understand "formal" - it could also be that the requested locale > > happens not to have "formal" day names, while the implementations supports > > "formal" and other locales have such names. > > Correct, but the above still holds as, IMO, "the right way"™ for a developer > to check if the API understood what the developer wanted (without the need to > throw an exception). > > > Note that there is precedence also in other APIs to not throw exceptions > > > on bogus options. For example, the Geolocation API does not throw in the > > > following cases and simply "just works" (tested in Chrome): > > > > > > var l = function(e){console.log(e)}; > > > navigator.geolocation.getCurrentPosition(l, l, {maximumAge:"bananas"}); > > > navigator.geolocation.getCurrentPosition(l, l, {maximumAge:Node}) > > > navigator.geolocation.getCurrentPosition(l, l, {maximumAge:{}}) > > > > > > > > > > > > Is that good? Without looking at the WebIDL spec, what are the maximumAge > > values derived from "bananas", Node, or {}? Although, I'm afraid you can > > provide the same nonsense in some options of the Internationalization API... > > It's good in as far that it's robust. In all bogus cases, the geolocation API > simply falls back to 0: "If a PositionOptions parameter was present, and its > maximumAge attribute was defined to a non-negative value, assign this value > to an internal maximumAge variable. If maximumAge was defined to a negative > value or was not specified, set the internal maximumAge variable to 0". > > Thanks for discussing this. Hopefully I've presented a coherent argument as > to why I think the change is important and clearly outlined the benefits for > both developers and users. > > Looking forward to this API being finalised and landing in browsers soon! :) > > Kind regards, > Marcos _______________________________________________ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss