[Numpy-discussion] Resolving the associativity/precedence debate for @
Nathaniel Smith
njs@pobox....
Sat Mar 22 13:13:45 CDT 2014
Hi all,
After 88 emails we don't have a conclusion in the other thread (see
[1] for background). But we have to come to some conclusion or another
if we want @ to exist :-). So I'll summarize where the discussion
stands and let's see if we can find some way to resolve this.
The fundamental question is whether a chain like (a @ b @ c) should be
evaluated left-to-right (left-associativity) or right-to-left
(right-associativity).
DATA SOURCE 1:
This isn't a democratic vote, but it's useful to get a sense of
people's intuitions. Counting messages in the other thread, opinion
seems to be pretty evenly split:
== "Votes" for right-associativity ==
Weak-right: [2] [3] [5]
Tight-right: [4] [6]
Same-right: [11]
== "Votes" for left-associativity ==
Same-left: [7] [8] [14] [15] [16]
Tight-left: [9]
Weak-left: [12]
There's also the "grouping" option (described in [10]), but that's
received very little support (just [13]).
DATA SOURCE 2:
Several people have suggested that performance considerations mean
that right-to-left evaluation is more common in practice than
left-to-right evaluation. But, if we look at actual usage in Python
code, that's not what we find: when people call dot() in chains, then
they're about evenly split, and actually use the left-to-right,
left-associative order slightly more often than the right-to-left,
right-associative order:
http://mail.scipy.org/pipermail/numpy-discussion/2014-March/069578.html
DATA SOURCE 3:
And if we look at other languages, then we find:
== "Votes" for right-associativity ==
<none>
== "Votes" for left-associativity ==
Same-left: Matlab, Julia, IDL, GAUSS
Tight-left: R
And Mathematica uses the "grouping" approach.
ARGUMENTS:
The final outcome of this is that I need to write a piece of text that
says what our (at least rough) consensus is, and lays out the reasons.
So long as the "vote" is so evenly split, I can't really do this. But
I can imagine what the different pieces of text might look like.
THE CASE FOR LEFT-ASSOCIATIVITY:
If I were writing this text in favor of left-associativity, I'd point out:
- "Special cases aren't special enough to break the rules". Every
single operator in Python besides ** is left-associative (and ** has
very compelling arguments for right associativity). @ does not have
similarly compelling arguments. If we were having this debate about
"*", then it'd probably be much more lopsided towards
left-associativity. So sure, there's something about @ that makes
right-associativity *more* appealing than for most other operators.
But not *much* more appealing -- left-associativity still comes out at
least slightly ahead in all of the above measures. And there are a lot
of benefits to avoiding special cases -- it gives fewer rules to
memorize, fewer rules to remember, etc. So @ may be a special case,
but it's not special enough.
- Other languages with @ operators almost overwhelmingly use the
"same-left" rule, and I've never heard anyone complain about this, so
clearly nothing horrible will happen if we go this way. We have no
comparable experience for right-associativity.
- Given left-associativity, then there's good agreement about the
appropriate precedence. If we choose right-associativity then it's
much less clear (which will then make things harder for experts to
remember, harder for non-experts to guess, etc.). Note that one of the
votes for right-associativity even preferred the "same-right" rule,
which is not even technically possible...
This strikes me as a nice solid case.
THE CASE FOR RIGHT-ASSOCIATIVITY:
If I were writing this text in favor of right-associativity, I'd point out:
- Because matrix multiplication has a tight conceptual association
with function application/composition, many mathematically
sophisticated users have an intuition that a matrix expression like
R S x
proceeds from right-to-left, with first S transforming x, and then R
transforming the result. This isn't universally agreed, but at the
least this intuition is more common than for other operations like 2 *
3 * 4 that everyone reads as going from left-to-right.
- There might be some speed argument, if people often write things
like "Mat @ Mat @ vec"? But no-one has found any evidence that people
actually do write such things often.
- There's been discussion of how right-associativity might maybe
perhaps be nice for non-matmul applications? But I can't use those
arguments [17] [18].
- ...... I got nothin'.
I am fine with any outcome here. (I'm actually listed under *both*
tight-right and same-left in the straw poll above ;-).) I'm totally
happy to go back to Guido et al and argue for right-associativity. BUT
if you all want me to do that then you need to give me some better
arguments to use :-).
One way to do this might be to go through the ((a @ b) @ c) and (a @
(b @ c)) examples I found (the scripts are available [19], and I can
help modify them to spit out more details), look at the actual code,
and demonstrate that the left-to-right ((a @ b) @ c) cases are mostly
ones where evaluation order doesn't matter (i.e., they could have just
as well been written the other way), and the right-to-left (a @ (b @
c)) ones are ones where right-to-left really is better than
left-to-right. I have no idea if this is true, and it'll require some
reading of the surrounding code to figure out what the matrix shapes
are, but if it *is* true then at least that'd be something solid that
right-associativity advocates could point to.
WHAT NOW:
If seeing this summary laid out caused you to change your mind one way
or the other, then please reply and say so!
If you think of some way to get more data that could favor one or the
other option (running some kind of usability experiment on people?
[20]), then please share!
If you think of some other arguments in favor of left-associativity,
then please share!
If you think of some other arguments in favor of right-associativity,
especially ones that are based on something besides your gut feeling,
then PLEASE PLEASE share!
Thanks,
-n
[1] http://mail.scipy.org/pipermail/numpy-discussion/2014-March/069444.html
[2] http://mail.scipy.org/pipermail/numpy-discussion/2014-March/069446.html
[3] http://mail.scipy.org/pipermail/numpy-discussion/2014-March/069450.html
[4] http://mail.scipy.org/pipermail/numpy-discussion/2014-March/069452.html
[5] http://mail.scipy.org/pipermail/numpy-discussion/2014-March/069455.html
[6] https://mail.python.org/pipermail/python-ideas/2014-March/027124.html
[7] http://mail.scipy.org/pipermail/numpy-discussion/2014-March/069512.html
[8] http://mail.scipy.org/pipermail/numpy-discussion/2014-March/069513.html
[9] http://mail.scipy.org/pipermail/numpy-discussion/2014-March/069467.html
[10] http://mail.scipy.org/pipermail/numpy-discussion/2014-March/069530.html
[11] http://mail.scipy.org/pipermail/numpy-discussion/2014-March/069537.html
[12] http://mail.scipy.org/pipermail/numpy-discussion/2014-March/069540.html
[13] http://mail.scipy.org/pipermail/numpy-discussion/2014-March/069571.html
[14] http://mail.scipy.org/pipermail/numpy-discussion/2014-March/069514.html
[15] http://mail.scipy.org/pipermail/numpy-discussion/2014-March/069531.html
[16] http://mail.scipy.org/pipermail/numpy-discussion/2014-March/069567.html
[17] http://mail.scipy.org/pipermail/numpy-discussion/2014-March/069527.html
[18] http://mail.scipy.org/pipermail/numpy-discussion/2014-March/069584.html
[19] https://gist.github.com/njsmith/9157645
[20] http://mail.scipy.org/pipermail/numpy-discussion/2014-March/069584.html
--
Nathaniel J. Smith
Postdoctoral researcher - Informatics - University of Edinburgh
http://vorpus.org
More information about the NumPy-Discussion
mailing list