Fallback

Peter van der Zee ecma at qfox.nl
Fri Feb 10 02:27:37 PST 2012


There's currently no way of introducing anything new into the language
that breaks syntax. I think that point has been made very clearly with
harmony/es6. Can we introduce a way to make these transitions easier
in the future?

CSS has a very simple way of gracefully ignore rules it doesn't know.
In CSS you can specify rules and features and whatever the engine
doesn't understand, it will ignore gracefully and continue. While this
obviously won't work out of the box for js. But I think we can work
around it. In CSS this is scoped to individual rules. In js there's no
notion of rules (and "lines" won't work either) but you could talk
about functions or modules (or blocks?) in the same way. I think
modules are a bit too big scoped for this but I'd like to discuss the
generic idea first. We can always bikeshed over the syntax later. I'll
work with function-like syntax for now.

Say a browser wanted to support a new keyword. Right now, that's
impossible to even experiment with unless you write an entire engine
in js and have a duplicate source code for fallback. You simply can't
do something like

x ||= y;

without breaking the code permanently and without exception. We can
only add stuff that fits perfectly within the existing grammar.
There's also no way for a vendor to implement this as an experiment
because it will still break in older versions of the browser or other
vendors. So what if we could do something like this?

function foo(x,y){
  "if es7";
  return x ||= y;
  "/es7";
} // the "/directive" serves as a delimiter because otherwise you'd
never know where to stop parsing when you don't support it
if (!foo) {
  var foo = function(){
    x = x || y;
    return x;
  }
};

So now you have a way to experiment with the new extension and a
simple way of extending the language permanently, while still having
backwards compat (at least up to the point that we introduce this
system), graceful failures and a proper way of figuring out a
fallback. If a vendor did not support the feature asked for it could
declare `foo` as null or something allowing easy support detection.

The declared function should work within the existing js language of
course and should be callable from within js with the regular
mechanics. This includes stuff like call, apply, and bind. Whatever
the function itself does with the arguments or the context is up to
the implementation. Whatever it returns should again be a proper js
value. This allows you to easily fallback to an "es5" function because
the fingerprint would be the same (and besides, I have no idea how
else this could work otherwise anyways).

This also could allow introduction of vendor prefixes. However, for
now I'd like to focus on the general principle though and leave the
prefix discussion for later.

Some syntax possibilities:

function foo(){ "es7"; x ||= y; }
function foo(){ "es7"; x ||= y; "/es7"; }
condFunction foo(){ "es7"; x ||= y; }
condFunction "es7" foo(){ x ||= y; }
condFunction "es7" foo(){ x ||= y; } "es7";

Personally, I'd prefer a function-scoped capability over a
module-scoped capability because I think I'd like to apply this to
smaller snippets rather than an entire module. Or maybe both.

Open things for me:
- How to efficiently specify the (scope of) things you want to opt-in to?
- How to limit the problem with interoperability this would
undoubtedly cause (even with prefixes).
- Proper keyword/syntax for this, would still like to keep this js-ish
- Is nesting desirable? Reasonably feasible? Especially wrt the delimiter
- This system would also allow for non-js extensions (like
coffeescript or even ruby/etc), is that a problem?

If we think such a system is viable and we can find a simple way of
introducing it to the language, we should do it sooner than later. The
sooner it's in, the less "stuck" we will be in the future.

- peter


More information about the es-discuss mailing list