I sent this mail to the JSMentors list yesterday [full thread]:
I’m announcing restrict mode for JavaScript, a proper subset of the language designed for improved program robustness. It’s opt-in similar to ES5 strict mode and enabled with a string literal ("use
restrict";
). Continue reading for an explanation of how it works and why I think it’s useful.
Operator semantics in regular (I call it loose) JavaScript are complex. In many cases the increased capabilities of this complexity doesn’t really outweigh the drawbacks, which include less robust programs and a language that’s both harder to learn for the beginners and harder to reason about for the experts.
Of course, this is nothing new. The idea of writing programs that for example perform advanced number arithmetics on operands of type strings seems silly. Still, the language lets us do exactly that. I’m arguing that much of the operator semantics complexity in the language, with corresponding type coercion, is not wished for. If we could make some of it go away, fewer bugs would hide and our programs would become more robust. It may also become even more fun to write and debug them.
This was discovered years ago when people started recommending the use of the (strict) ===
operator instead of the (loose) ==
operator, and the same for !==
vs !=
. It’s entirely possible to write programs without using the ==
operator at all, and many programmers have chosen to do so. The result? More robust programs that are easier to reason about. For a beginner, it’s also a programming style that’s easier to learn and master.
The problem is that there is no strict version of the (loose) <
operator. Or >
, <=
, >=
, +
or -
and so on and so forth. Because these are loose and loose-only, we’ve kind of accepted them as-is and moved on. Imagine for a second what would happen if you suddenly had strict versions of these operators available, with the possibility of making the strict versions the default for parts of your program. How would you then define the strict version of <
? I bet you wouldn’t want it to accept an operand of primitive type number and another of primitive type string, since that would most likely be a bug in your program. Would you want it to accept undefined < 3
? I bet not. Perhaps you would like to get notified as early as possible with an exception if your strict rules are broken?
Here’s the thing. We already limit ourselves to a subset of the semantics for these operators. At least we try to. We don’t mix strings, numbers and booleans randomly. We don’t perform arithmetics to undefined
, on purpose. We try to be in control of when type conversion happens, and so on. It’s just that we don’t necessarily use precisely the same subset, because we haven’t really though about what we should be restricting our programs to. And we don’t have any good means of getting notified as soon as we break that subset. We would like to, because no matter how good we are at this language, we still have to fix defects in our code. Defects some of which are related to breaking the subset.
As you might have guessed by now I’ve defined such a subset and created a tool that modifies a JavaScript program so that it throws an exception whenever the subset is broken. I call the subset restrict mode for JavaScript and would like to get your feedback on it. It’s opt-in similar to ES5 strict mode, and you can easily opt-out for any part of your program. The tool is called restricter
. It’s a plugin for JSShaper, an extensible framework for JavaScript syntax tree shaping.
The restricter-modified program should be used when running your test suite. Since restrict mode is a proper subset of regular JavaScript, you can still deploy the original program.
Here are the restrict mode rules:
0. === and !==
are already strict by default, with identical semantics in
restrict mode
1. == and !=
are restricted to undefined == null (true) and
undefined != null (false). They are otherwise only allowed
when the === or !=== operator yields an identical result
2. + < <= >= >
are restricted to primitive strings or numbers
(but never a mix)
3. - * / % & | ^ ~v << >> >>> -v ++v v++ --v v--
are restricted to primitive numbers
4. That's it!
+v !v && || ?: o[k] and all other operators
have identical semantics in restrict mode
Many programs already conform to most of these rules, with the notable exception of the restrict +
operator in clause 2. In restrict mode you can no longer use str + nostr
to perform string conversion and concatenation at the same time. You can easily replace this with a call to a string-formatting function (I use Fmt
) or an explicit conversion via String(nostr)
.
Clause 1 is a compromise and may need to change. I’d rather see ==
and !=
disallowed but there seem to be many programs relying on the undefined == null
behavior. For now I’ve added a pedantic setting where it’s disallowed.
I’d like to hear your thoughts on all this. Does restrict mode resonate with you and if so, do the rules define the right subset?
I have a preliminary web site up at http://restrictmode.org/ with more information. You can try restrict mode live in your browser by following the “Try restrict mode” link. Source code for JSShaper is available at https://github.com/olov/jsshaper.
/Olov
Follow me on Twitter
« Announcing restrict mode for JavaScript ↑ Home C-style assertions in JavaScript via JSShaper »