Should (1 + #A) Equal (#A + 1) ?

I ran across this peculiarity:

rebol2>> 1 + #"A"
== 66

rebol2>> #"A" + 1
== #"B"

Red and R3-Alpha do this too.

Loosely speaking, there's an internal policy which is something along the lines of "if the types don't match, convert the second operand into the type of the first, and then do the add".

Because of this, it's necessary to support the addition of characters to each other to get (#A + 1) to work:

red>> #"A" + #"B"
== #"^(83)"  ; only useful in implementation of old coercion rule

...which seems nonsensical to me.

What Do Other Languages Do?

If "implicit type promotion" is supported, many languages, including C, C++, and Java, use a system where the "smaller" type is converted to the "larger" type (e.g., int to float). Having an idea of what's bigger and what's smaller helps avoid the commutativity problem.

And in the specific case of adding characters to integers, Rebol is weird to give a different answer depending on order.

  • Python: In Python, adding an integer to a character (or vice versa) would raise a TypeError. Python doesn't implicitly convert between these types.

  • JavaScript: JavaScript would convert the character to its ASCII value and perform integer addition in both cases, resulting in a number.

  • Ruby: Similar to Python, Ruby would raise a TypeError when trying to add an integer to a character.

  • Java: Java doesn't allow direct addition between char and int types without explicit casting.

I think adding integers to characters and wanting a character back is the more common operation, so if it's legal, I'd advocate for:

>> 1 + #A
== #B

>> #A + 1
== #B

But if we want to rule out addition of characters to characters (which I do) this commutative behavior doesn't fall out from a system of implicit conversion with an ordering on "bigger" types... since characters are smaller.

I don't see an obvious "rule" besides hardcoding it.

What About Commutativity In General?

We can imagine decisions on what you would make + mean that would not be commutative. For instance, if you were allowed to make it mean "join strings":

>> "abc" + "def"
== "abcdef"

>> "def" + "abc"
== "defabc"

So you might try and argue that the rules for add are different than the rules for +, and it's only when + is acting as ADD that it enforces commutativity. However... even in the domain of math, you have exceptions... e.g. matrix multiplication is not commutative.

The more general question of commutativity seems to be that there aren't any popular languages that do it automatically. e.g. in C++ you have to overload operator+(T1,T2) and operator+(T2,T1) separately...one of them can call the other, but that never happens automatically.