Poll: Operator Precedence
I've been doing a lot of thinking about operator precedence (and the lack thereof) in highly programmable languages. When the entire language is defined via macros (all user-facing constructs and operators), it becomes very difficult to parse code using operator precedence. You have to defer the grouping of operands until well after the actual parse-time. In addition, you could have the same operator with different precedence depending on the macros in scope.
To alleviate these issues, I've been considering doing away with operator precedence entirely, and making everything left-to-right (with parentheses and other grouping operators). My concern is that this could make the language highly undesirable to many developers, so I'd like to get a general feel for how you guys feel about this idea.
(Thanks to the people who responded to http://news.ycombinator.com/item?id=1027796 , where I originally talked briefly about this idea)
19 comments
[ 2.8 ms ] story [ 40.8 ms ] threadWhy do you want to have the whole language defined through macros?
You have to defer the grouping of operands until well after the actual parse-time.
Why?
you could have the same operator with different precedence depending on the macros in scope.
But if your macros have scope, isn't this a problem independent of operator precedence?
I'd suggest defining higher-order macros, where you can have a something like infix(op, prec=0, assoc=LEFT), used like:
For a similar example, see Haskell's infixr/infixl: http://www.haskell.org/tutorial/functions.html#sect3.2.2Also, whatever it is you are doing might be easiest to implement using Alex Warth's OMeta: http://tinlizzie.org/ometa/
Why?
Well, in the case of my parser, I get back an S-expression corresponding to the groups (parentheses, braces, brackets) in the code, with each token inside that. So to group expressions, I then have to go over that, applying the macros in order of precedence. If I make operators purely left-to-right (with the exception of . , which has to be special-cased), I can do this grouping at the parser level and simplify things.
But if your macros have scope, isn't this a problem independent of operator precedence?
It's still a problem, as it is with any language with macros, but by letting operators have precedence that can change from file to file (or even worse, from function to function, if you're sadistic) would make it very difficult for people to track what's going on. With the pure left-to-right parsing, the behavior of operator grouping would be consistent regardless of anything else that's going on.
For example:
looks fine with parens: but when it becomes slightly more complicated: it really looks awkward.Or how about this?
is parsed as and I'd really hate to have to write simple assignments as just to avoid that kind of snafu.I don't think your compiler should get much more complicated with operator precedence. Just have a precedence stack that always reflects the operator precedence in the current scope. Parse the expressions without operator precedence (e.g. always LtR), then at a later compilation stage, swap the subexpressions in the AST until the AST adheres to the precedence rules, and you're done.
As for assignments, this would actually be a nonissue. For example, x = 5 + 10 would be parsed as:
Same with a = b = c + d: Edit: Hmm, I was just thinking about this, and this order of parsing could potentially cause issues. It'd work for most arithmetic, but in the case of complex operations (specifically operator overloads on things like matrices) it could cause problems. I need to think a bit more on this issue.I'm not sure if I could get used to
getting parsed as It would also be really awkward when considering slots/accessors/etc surely should never be:http://en.wikipedia.org/wiki/Smalltalk#Expressions
if i find myself having to maintain code like that, first i'll write unit tests, then add parentheses where i think they ought to go, and make sure the tests still pass.
TeX is an entirely macro-driven language. It processes an input file by reading a token (usually a single letter or a backslashed \command), and then either executing the token if it is a builtin operator or replacing the token with its macro definition. Since it is always processing the first token on the list, it has no operator precedence concerns (in essence, everything is in prefix notation).
Metafont (the programming language Knuth created for drawing fonts) is also a macro language, but it allows for infix notation as well as prefix. When you define an infix operator macro, you can choose a precedence level (primary, secondary, tertiary). For example (I'm not sure if this is exactly right), addition might be a tertiary operator, multiplication a secondary operator, and exponentiation a primary.
Having used both of these languages fairly extensively in the past, I would say that the easiest way to avoid the issue of operator precedence is to disallow infix operators. However, if you do think that infix operators are worth keeping in your language, you might look to the Metafont parser implementation for ideas--if there is anyone who has something to say on parsing, it is Donald Knuth.
Most of the time operator precedence works according to the BODMAS rule. Doesn't it?
Second, I have never programmed in an infix-notation language without operator precedence, and I imagine most programmers are like me. I can't possibly know if I will continue to make stupid mistakes due to my intuition about precedence for just a couple of days after learning the language, a couple of months, years, or forever.
That said, I would encourage you to try the language without precedence and ask early adopters about their experience. If it is at all possible to have precedence in your way of doing things and it turns out to be needed enough, you can implement it later.
I'd say it's only a problem if you want to go mainstream.
Looking at the discussion it seems like you would have to formulate your language as a whole and have sample to show people before you could determine if operator precedence "brakes the deal". I mean, meaningful whitespace breaks the deal for me in python but it works for a lot of people but suspect it only works in the context of everything else in that language.