[Apologies for resending, trying to fix formatting of grammar excerpts. /be]

Quick update from TC39 yesterday where Rick and I presented the Stage 3 Exponentiation Operator proposal:

http://rwaldron.github.io/exponentiation-operator/

The current spec, revised to match precedent from all known programming languages that have exponentiation operators, binds

-x^y = -(x^y )

and not

-x^y = (-x)^y

as the original proposal specified. These examples use Math notation, but the proposed exponentiation operator is infix ** of course. And that's the source of trouble for this proposal.

The problem is, however rare unary minus before an exponentiation expression may be, the lack of superscript-with-smaller-font sugests that - binds tighter than **. And indeed apart from dot (a special form whose right operand must be a lexical identifier-name) and square brackets (which isn't an infix operator per se), unary operators bind tighter than binary in JS as in C and other C-derived languages.

Yehuda suggested that exponentiation was "cargo-culted" from Math into Fortran, and then into other languages, without considering the notational shift and the apparent precedence inversion. I don't know the history, but it's plausible, and numerics folks probably would not expect unary - to bind tighter than exponentiation. But JS programmers may see -x and especially -2 as a tighter expression, if not a single lexeme, than any expression joined by infix **.

We debated the options, which I think are four in number:

1. Give up because the proposal has hit a "wall of confusion".

2. Stick with the current spec,

3. Go back to the old spec, which flouts precedent.

4. Make unparenthesized exponentiation expression as operand of unary operators an early error.

I came up with (4) late in the day, and it didn't get a fair hearing. Before I wrote it up on the board, I asked for a straw poll (those can bite back by forcing people onto a bandwagon, as Dave Herman pointed out) on (1-3). The poll favored (2), with notable but minority positions for (1) and (3).

The grammar change needed for (4) is trivial. Instead of

UnaryExpression_[Yield] :
IncrementExpression_[?Yield]
    delete UnaryExpression_[?Yield]
    void UnaryExpression_[?Yield]
    typeof UnaryExpression_[?Yield]
    + UnaryExpression_[?Yield]
    - UnaryExpression_[?Yield]
    ~ UnaryExpression_[?Yield]
!UnaryExpression_[?Yield]
IncrementExpression_[?Yield] ** UnaryExpression_[?Yield]

we factor to require parentheses around the last right-hand side if it is an operand of a unary operator:

UnaryExpression_[Yield] :
SimpleUnaryExpression_[?Yield]
IncrementExpression_[?Yield] ** UnaryExpression_[?Yield]

SimpleUnaryExpression_[Yield] :
IncrementExpression_[?Yield]
    delete SimpleUnaryExpression_[?Yield]
    void SimpleUnaryExpression_[?Yield]
    typeof SimpleUnaryExpression_[?Yield]
    + SimpleUnaryExpression_[?Yield]
    - SimpleUnaryExpression_[?Yield]
    ~ SimpleUnaryExpression_[?Yield]
!SimpleUnaryExpression_[?Yield]

(It would be nice to rename non-terminals like so: s/\<UnaryExpression\>/ExponentiationExpression/g; s/\<SimpleUnaryExpression\>/UnaryExpression/g where \<\> are left and right word boundaries -- but I'm leaving this out for now since it touches more of the spec and is merely a nominal change.)

Thus one may write

let z = K - x**y;

without having to parenthesize unduly, but one cannot write

let z = -x ** y;

The user is forced by an early error to write either (-x)**y or -(x**y).

The early error stops parsing with a thrown SyntaxError.

It seems to me (4) wins and rescues the proposal at stage 3 from suffering a loss of consensus. Comments welcome.

/be

Jason Orendorff wrote:
Don't rely on github searches to turn up representative examples. It
doesn't work that well. Here's my educated guess as to how ** will be
used.

The most common use will be to square numbers.

     a²
     a**2
     Math.pow(a, 2)
     a.pow(2)

Currently you might write `a * a`, which is kind of lame.

So where's the benefit? If this trivial thing is the most common use
of exponentation, why bother?

The ability to look at an expression and understand it at a glance is
a big deal.

     x² + y²>  limit
     x**2 + y**2>  limit
     Math.pow(x, 2) + Math.pow(y, 2)>  limit
     x.pow(2) + y.pow(2)>  limit

A big big deal. It's the reason we have arithmetic operators in JS in
the first place.

Exponentiation is common when computing easing functions, curves for
graphics, interest, simulations, random stuff in games. Nth roots are
fairly common too (`apr**(1/12)`). In all of these cases, the user is
doing the same thing: translating a mathematical formula they wish to
use from "math" to JS. It is not extra hard to translate such a
formula using Math.pow(), but it is harder to read once you're done.
You have to mentally translate back to "math".

-j
_______________________________________________
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to