I've been mulling over my RFC on a replacement for `dotOperator`. I wrote that RFC because this RFC on modifying dot-like operator precedence (#341) was labelled "let's see what breaks accepted", and I really wanted to get to a better solution. I'm still looking for a better solution, so I'm looking for feedback on this idea:
What if operator precedence was overridable?
I know it sounds like a terrible one given how flexible Nim already is, but hear me out!
I read somewhere in the forums that someone once suggested to add overridable operator precedence to the compiler, and it seemed that Araq had flat out refused. I think there are several good reasons to not allow this, the most important for me being: it's hard to understand code that looks exactly the same but behaves differently. But could the advantages of this feature outweigh its disadvantages if it were limited somehow?
What do you guys think about this feature, but with the following limitations:
I guess "built-in operators" would have to be defined for limitation #1. Built-in operators could be the ones for basic types, like ., +, -, etc (maybe a list similar to Dlang's?).
Essentially, this is a superset of the solution suggested in RFC 341. It gives more control over the behavior of operators, and doesn't introduce special casing. At the same time, it is (probably) not as radical as my RFC, and could be a safer addition.
The only language I've used that has this feature is Swift, and people use it there for some weird-looking operators. I also noticed that Dlang doesn't have this feature, but that language limits the operators that can be overloaded (whereas Nim limits the characters that can be in an operator), so it makes sense not to have this feature there. I think Nim sits quite snugly in between those two languages in terms of operators, so maybe this feature could be an addition that makes sense?
As for the syntax, that could simply be in the form of a special pragma attached to the operator being defined.
Nim was designed to be parsable without a symbol table and this feature would break this design. You can come up with post-parse rewrite rules (which is also what Haskell does iirc), in fact, you could implement these rules via a macro. But I don't like it and I don't see why we would need it.
Nim's design isn't arbitrary, there are no special rules for "builtin" operators and it should stay this way.
let's see what breaks accepted
I spent a morning trying to implement that RFC, which was supposed to be a simple change in operator precedence for .* I soon found that much special casing has been written into the parser around 'x.y' and that 'precedence' is a fuzzy beast indeed
special casing has been written into the parser
Last time I checked Nim had a grammar and the parser reflects the grammar...
I know we're all used to operator precedence from elementary school and in programming languages, but beyond the very basic rules, most people find them very confusing -- especially with semantics vs syntax (e.g., many people assume << in C has the same precedence as * because they are both multiplications).
The less cognitive load needed in mental parsing, the less likely such mistakes will be made. Also, being able to parse without a symbol table is an excellent feature to have - thanks, Araq.
APL/K/J do away with operator precedence completely. There is only one precedence, and all operators ("verbs") are right-associative (alsk known as "right-to-left" or "left-of-right" evaluation). It takes a few days to get used to, but it is so simple and useful.
(They do have another class, called "adverb", which is different - but it doesn't mix with verbs in any confusing way. APL and J cannot be parsed without a symbol table; K can)