You can explore this some using objects if you like. So take this:
a-(-a)
Alright, that’s not ambiguous and makes sense because of the parenthesis. Now if you get rid of those:
a - -a
It’s ambiguous in a language with --. Do you mean the first one, or a --a which is a syntax error. Python though doesn’t have – so that means it’s using the first one, which is fine. Ok great. However, what does this mean?
a - --a
If you try to do use parenthesis to disambiguate this then you’d get:
a - (- (-a)).
Now suddenly the middle - is ambiguous because do you mean:
a minus (negative (negative a))
or
a minus (minus (negative a))
If it’s the first one, then why is it not then “a negative (negative (negative a)”? Because that’s a syntax error since the unary minus only applies to one operand. If it’s the second one then why isn’t is “a minus (minus (minus a)”? Again, because that’s a syntax error because binary minus needs two operands on either side and the parenthesis around the middle one block that.
The way you solve it is to simply decided what one you want and then go with it, but there’s an interesting implication to it when you have object oriented programming. Let’s say I have some objects that intercept __sub__
and __neg__
so I can do obj1 - obj2
and get something meaningful. Take a look:
>>> class SubTest:
... def __neg__(obj):
... print("neg", obj)
... return obj
... def __sub__(obj, x):
... print("neg", obj)
... return x
...
>>> left = SubTest()
>>> right = SubTest()
>>> left
<__main__.SubTest object at 0x7f9b74c8b4e0>
>>> right
<__main__.SubTest object at 0x7f9b74c8b4a8>
>>>
>>> left ----right
neg <__main__.SubTest object at 0x7f9b74c8b4a8>
neg <__main__.SubTest object at 0x7f9b74c8b4a8>
neg <__main__.SubTest object at 0x7f9b74c8b4a8>
neg <__main__.SubTest object at 0x7f9b74c8b4e0>
<__main__.SubTest object at 0x7f9b74c8b4a8>
>>>
You can play around with “operator overloading” using this https://docs.python.org/3/reference/datamodel.html#emulating-numeric-types and it looks like Python takes the first -
and treats it like subtract, then all subsequent -
are negation, which makes sense since Python doesn’t have --
.
Basically, it’s not really “wrong”, since it’s just a design decision and it works in the universe of Python. It is however a questionable design decision given the universe of other languages that do have --
or ++
as operators. Programmers coming from those languages will run into bugs if they accidentally use that without knowing that this happens. In fact, I bet this is one of the reasons Python doesn’t have these operators. They decided to do this for multiple negation math and then ooops oh uhhhhhhhhhhh ok no – operator then.