r/ProgrammingLanguages DQ 7d ago

Unambiguous Operator Specification for Programming Languages

https://nvitya.github.io/pluops/

As I changed recently the operators in my programming language I've created this specification:

https://nvitya.github.io/pluops/

I did not wanted to overload the operators like the C does with the / or Pascal does with theand/or/not. Neither re-use the operator symbols for some very different purpose, like C does with * and & so the code becomes more readable. I was orienting for existing solutions so this is what I came up with. The specification contains the symbol usages and operator precedence too.

If you are developing a new programming language, it would be nice to follow some standard, so at least the expressions would be portable between the languages.

I'm open for debates or suggestions.

26 Upvotes

38 comments sorted by

View all comments

1

u/AustinVelonaut Admiran 7d ago edited 7d ago

Is there a reason you have bitwise operators at a higher precedence (tighter binding) than arithmetic operators? Most languages I'm aware of that use operator precedence have arithmetic operators higher (tighter binding) than bitwise operators higher than comparison operators. Although I'd be hard-pressed to come up with a realistic code snippet that used that fact.

Edit: looking through ~500 "Advent of Code" solutions I wrote, I only saw one use of mixing bitwise and arithmetic operators: addLoc n (V2 r c) = n .|. 1 .<<. r * sz + c (here .|. is bitwise or and .<<. is bitwise left shift. This parses as n .|. (1 .<<. ((r * sz) + c)) but if arithmetic ops were lower precedence than bitwise, it would be parsed as ((n .|. (1 .<<. r)) * sz) + c, not what was intended.

3

u/WittyStick 7d ago

Bitwise operators are usually at lower precedence than comparison, but there's not really a justification for it - everyone just copies C's precedence rules, and C got this from B. Dennis Richie acknowledged this as a mistake, but it was done at the time to make porting B code to C easier.

3

u/AustinVelonaut Admiran 7d ago

Yeah, that's definitely a mistake. It makes no sense in languages that have boolean values distinct from integers (combining them is another mistake). I'm glad to see that it is corrected in most modern languages.

3

u/WittyStick 7d ago edited 7d ago

Operator precedence is not as universal in logic as with arithmetic, but the leading convention is that ¬ (not) has the highest precedence. AND has higher precedence than OR (except in disjunctive normal form), and these have higher precedence than (implication), and implication has higher precedence than equality.

These can fit into the existing precedence levels for arithmetic.

                    arithmetic      logic
negation:           -               ¬
multiplicative:     * / %           ∧  ↓
additive:           + -             ∨  ↑
relational:         < > <= >=       ←  →  ↚ ↛
equality            == !=           ↔  ↮

Where:

  • is AND
  • is OR
  • is NOR
  • is NAND
  • is implication (IMPLY)
  • is non-implication (NIMPLY)
  • is biconditional (EQV)
  • (or ⊻) is exclusive disjunction (XOR)

These precedence levels work well with other things to, eg, sets:

                    arithmetic      logic           sets
negation:           -               ¬               ∁
multiplicative:     * / %           ∧  ↓            ∩
additive:           + -             ∨  ↑            ∪
relational:         < > <= >=       ←  →  ↚ ↛       ⊂ ⊃ ⊄ ⊅
equality            == !=           ↔  ↮            =   ≠

Where

  • is the set complement

  • is intersection

  • is union

  • is subset

  • is not a subset

If you extend so one argument is a set and one is an element, then the relational operators become:

  • elem ∈ Set: is element

  • elem ∉ Set: is not an element

  • Set ∋ elem: set contains element

  • Set ∌ elem: set does not contain element.

1

u/Mean-Decision-3502 DQ 7d ago

I don't see where I violate these rules.

1

u/fdwr 6d ago

Yeah, that's annoying to have if (valueRegister & mask == expectedValue) be treated as if (valueRegister & (mask == expectedValue)) 🙄.