Update: This proposal now has two open bugs for implementation, on V8 and SpiderMonkey.
In this article, I’ll explore the process of adding syntax to a programming language by going through the process of designing a new JavaScript exponentiation operator, which I’ve submitted to TC39 for consideration in ES7.
In many programming languages, exponentiation is written with a syntactic arithmetic operator expression form; most commonly as x ** y
(Python, F#, Ruby, Perl, et al.), or x ^ y
(BASIC, Lua, MATLAB, R, et al.). Other languages including JavaScript or C# rely on built-in objects to provide a function to call: Math.pow
and Math.Pow
.
To design an exponentiation operator for JavaScript, it makes sense to borrow an established syntax, this will have impact on both teachability and learnability, as it takes advantage of an existing mental model and definition associated with a visual form. From the two designs described in the previous paragraph I’ve chosen the **
form because the character ^
is already in use as JavaScript’s bitwise XOR
operator. The **
form is complimented by a compound assignment operator form: **=
. The semantics are defined as matching those of the built-in Math.pow
function (assuming that it is the original Math.pow
as defined by Ecma-262).
- 24 = 1 * 2 * 2 * 2 * 2 = 16
- -2-4 = 1 / -2 / -2 / -2 / -2 = 0.0625
In existing and proposed JavaScript forms:
Math.pow(2, 4) === 16;
Math.pow(-2, -4) === 0.0625;
2 ** 4 === 16;
-2 ** -4 === 0.0625;
var a = 2;
var b = -2;
a **= 4;
a === 16;
b **= -4;
b === 0.0625;
Before defining a new syntactic form for ES7, we’ll look at the existing arithmentic operator grammar definitions. In ES5 (and ES6) MultiplicativeExpression
has the highest arithmetic operator precedence after UnaryExpression
and is followed by AdditiveExpression
(and so on):
MultiplicativeExpression[Yield] :
UnaryExpression[?Yield]
MultiplicativeExpression[?Yield] MultiplicativeOperator UnaryExpression[?Yield]
MultiplicativeOperator : one of
* / %
…Which means that the following two expressions have the same result:
-2 * 2 + 1 === -3;
1 + -2 * 2 === -3;
This is because they are evaluated in exactly the same order, despite being written in different order. The order is:
- unary (
-2
) - multiplication (
-2 * 2
) - unary (
-4
, the result of step 2) - addition (
-4 + 1
,1 + -4
)
Exponentiation must be evaluated before multiplication and more importantly, the BNF grammar must be written such that the operator’s right-associativity is clearly defined (unlike MultiplicativeExpression
, which is left-associative). The following invariant illustrates the associativity requirement:
a ** b ** c === Math.pow(a, Math.pow(b, c));
A new ExponentiationExpression
definition will replace the UnaryExpression
definition in MultiplicativeExpression
; the change looks like this:
ExponentiationExpression :
UnaryExpression[?Yield]
UnaryExpression[?Yield] ** ExponentiationExpression[?Yield]
MultiplicativeExpression[Yield] :
ExponentiationExpression[?Yield]
MultiplicativeExpression[?Yield] MultiplicativeOperator ExponentiationExpression[?Yield]
MultiplicativeOperator : one of
* / %
AssignmentOperator : one of
=
*=
/=
%=
+=
-=
<<=
>>=
>>>=
&=
^=
|=
**=
As of this year, TC39 adopted a 4-stage process for vetting proposed changes to the ECMAScript specification. This model is designed to hopefully facilitate a faster specification release period. I presented this proposal at the last face-to-face meeting as a Stage 0 proposal for ES7 with Stage 1 criteria already complete. Shortly before being presented, and based on the strawman proposal, Erik Arvidsson implemented the operator as an experimental feature in Google’s Traceur Compiler. The proposal is publicly available and progress can be tracked by following the tc39/ecma262 repository.