You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@groovy.apache.org by Paul King <pa...@asert.com.au> on 2015/06/06 13:08:56 UTC

precedence rules for power operator vs -, +, ++, --

Hi everyone,

As part of documenting the existing behavior for Groovy in Action 2nd Edition, we noticed an anomaly with precedence rules for the power operator. It is different compared to all the other operators, e.g. "+", "*", etc., with respect to unary minus, unary plus, increment and decrement. We are intending to fix this anomaly
in Groovy 2.5. This is documented as a breaking change in the normal way within the release notes but thought it was worth also giving an additional heads-up email for any users of the power operator so they can perform any remedial work well in advance of 2.5. No date yet has been set for 2.5, but we hope to release a beta version in the not too distant future.

In a nutshell, if you have expressions like:

x ** y      // you aren't affected regardless of whether x and y are +ve or -ve
x ** -y     // you aren't affected; the anomaly is only on the left-hand expression
(-x) ** y   // you aren't affected; bracketing takes precedence
-3 ** 2     // if you want to keep the existing behavior, we recommend you bracket like this: -(3 ** 2)

Before the change, the following executes:

def x = 5
assert -x ** 2 == -25  // treated as -(x ** 2)
assert --x ** 2 == 24  // treated as --(x ** 2)

This behavior is different to the other operators and different to what the comments in the grammar describe as the intended behavior but the order of two rules was presumably accidentally reversed in the grammar.

After the change, the following executes:

def x = 5
assert -x ** 2 == 25   // treated as (-x) ** 2
assert --x ** 2 == 16  // treated as (--x) ** 2

At this stage, we aren't planning to write a migration tool but such a tool wouldn't be too hard to write if anyone has a huge migration task ahead of them. We suspect that most people have probably already put in brackets or used variables which might themselves be -ve, so as not to have weird behavior but some occurrences in the current form might also no doubt exist.

Further details:
https://issues.apache.org/jira/browse/GROOVY-7428


Cheers, Paul.

---
This email has been checked for viruses by Avast antivirus software.
https://www.avast.com/antivirus


RE: precedence rules for power operator vs -, +, ++, --

Posted by "Winnebeck, Jason" <Ja...@windstream.com>.
Yes, given that Jochen saw precedence in Python and Lua for power operator to have higher precedence than unary, and it has precedence in written math, and it’s already working that way in Groovy now, I don’t think it should ever change, but that’s just my opinion.

As for the breaking changes, I’ve mentioned them on the list in the past. I’m not sure I’ve done any major Groovy version upgrade without at least one disappointing breaking change. I’m not talking about purposeful ones (except for the change that had to be made to sort for Java 8 compatibility), but regressions and unintended changes. The most recent one was the change where if a class has “isX” and “getX”, it used to call getX but then it started calling isX (or maybe it was the other way around). I think this was upgrade from 2.3 to 2.4 Then upgrade from 2.2 to 2.3 and I run into closures in children classes can’t call static methods in their parents: https://issues.apache.org/jira/browse/GROOVY-6883. In the earlier 2.x days, I believe I ran into issues where code that used to compile with @CompileStatic didn’t after some type checker changes, but the static compiler is a lot more stable now, although I still run into issues on a daily basis: one is given interface X and interface Y extends X, you cannot import static Y and use the constants of X (as you can in Java, and as IntelliJ can auto-import for you) -- https://issues.apache.org/jira/browse/GROOVY-7460. The second is a case in nested closures where there is a delegate and I’m accessing a property, the code resolves properly in IntelliJ but the generated bytecode issues a call to the “this” (parent) class instead so I get NoSuchMethodError, and when this happens I replace the .prop with .getProp(). For that one I’ve not been able to reproduce in isolation yet, so no JIRA but it happens to me and my teammates a bit. In these cases it’s bugs but it also contributes to the “every version of Groovy is different.” So I have to think about issues like https://issues.apache.org/jira/browse/GROOVY-6891 where if I go back before 2.4 I have to remember that I can’t rely on overloaded setters in compile static, so it’s a sort of “mental” breaking change as I have to keep these in mind. I love Groovy, a lot, and by no means do I want to downplay the effort of the developers on it (and I know how much I’m paying for it), but while it is by far my favorite development environment for the past few years I have to admit to people that I run into issues a lot on just fundamental things and hold back on a blanket endorsement.

Jason

From: Cédric Champeau [mailto:cedric.champeau@gmail.com]
Sent: Monday, June 08, 2015 12:02 PM
To: users@groovy.incubator.apache.org
Subject: Re: precedence rules for power operator vs -, +, ++, --



2015-06-08 15:02 GMT+02:00 Winnebeck, Jason <Ja...@windstream.com>>:
If this isn't a clear cut fix then you might want consider leaving it as it is for backwards compatibility. Groovy already has enough issues with breaking changes.

I agree that we should avoid breaking changes on this on a dot release. It's not really a bugfix but a semantic change. That said, can you elaborate on "Groovy has enough issues with breaking changes"? In general we do a pretty good job I think to preserve compatibility. What problems did you face? Were those problems documented as breaking changes? If not, were they simply bugs?

----------------------------------------------------------------------
This email message and any attachments are for the sole use of the intended recipient(s). Any unauthorized review, use, disclosure or distribution is prohibited. If you are not the intended recipient, please contact the sender by reply email and destroy all copies of the original message and any attachments.

Re: precedence rules for power operator vs -, +, ++, --

Posted by Cédric Champeau <ce...@gmail.com>.
2015-06-08 15:02 GMT+02:00 Winnebeck, Jason <Ja...@windstream.com>
:

> If this isn't a clear cut fix then you might want consider leaving it as
> it is for backwards compatibility. Groovy already has enough issues with
> breaking changes.


I agree that we should avoid breaking changes on this on a dot release.
It's not really a bugfix but a semantic change. That said, can you
elaborate on "Groovy has enough issues with breaking changes"? In general
we do a pretty good job I think to preserve compatibility. What problems
did you face? Were those problems documented as breaking changes? If not,
were they simply bugs?

Re: precedence rules for power operator vs -, +, ++, --

Posted by Paul King <pa...@asert.com.au>.
After further discussion, this change was rolled back.
See GROOVY-7428 for further details. Some of the comments
in the grammar file don't match the current implementation
andlook like they are leftover from very early (pre 1.0)
days. These comments will be aligned with the current
implementation.

Cheers, Paul.

On 9/06/2015 5:55 AM, Paul King wrote:
>
> Yes, this is 2.5 only - but I'll probably roll back the change - after checking a
> few more languages to make sure we  make a fully informed decision.  There is
> definitely precedence in both directions.
>
> Cheers, Paul.
>
> On 9/06/2015 2:53 AM, Pascal Schumacher wrote:
>> Am 08.06.2015 um 18:49 schrieb Jochen Theodorou:
>>> Am 08.06.2015 15:12, schrieb Graeme Rocher:
>>>> Agreed, I wouldn't break binary compatibility in a minor release, if
>>>> this change is to be made it should be done in the next major release
>>>> branch IMO
>>>
>>> just want to point out, that this is no change that breaks binary compatibility.
>>>
>> Also the change is for master (2.5) only. We do not intend to apply it to the 2.4-Bugfix branch.
>>
>
>
> ---
> This email has been checked for viruses by Avast antivirus software.
> https://www.avast.com/antivirus
>
>


---
This email has been checked for viruses by Avast antivirus software.
https://www.avast.com/antivirus


Re: precedence rules for power operator vs -, +, ++, --

Posted by Paul King <pa...@asert.com.au>.
Yes, this is 2.5 only - but I'll probably roll back the change - after checking a
few more languages to make sure we  make a fully informed decision.  There is
definitely precedence in both directions.

Cheers, Paul.

On 9/06/2015 2:53 AM, Pascal Schumacher wrote:
> Am 08.06.2015 um 18:49 schrieb Jochen Theodorou:
>> Am 08.06.2015 15:12, schrieb Graeme Rocher:
>>> Agreed, I wouldn't break binary compatibility in a minor release, if
>>> this change is to be made it should be done in the next major release
>>> branch IMO
>>
>> just want to point out, that this is no change that breaks binary compatibility.
>>
> Also the change is for master (2.5) only. We do not intend to apply it to the 2.4-Bugfix branch.
>


---
This email has been checked for viruses by Avast antivirus software.
https://www.avast.com/antivirus


Re: precedence rules for power operator vs -, +, ++, --

Posted by Pascal Schumacher <pa...@gmx.net>.
Am 08.06.2015 um 18:49 schrieb Jochen Theodorou:
> Am 08.06.2015 15:12, schrieb Graeme Rocher:
>> Agreed, I wouldn't break binary compatibility in a minor release, if
>> this change is to be made it should be done in the next major release
>> branch IMO
>
> just want to point out, that this is no change that breaks binary 
> compatibility.
>
Also the change is for master (2.5) only. We do not intend to apply it 
to the 2.4-Bugfix branch.

Re: precedence rules for power operator vs -, +, ++, --

Posted by Jochen Theodorou <bl...@gmx.org>.
Am 08.06.2015 15:12, schrieb Graeme Rocher:
> Agreed, I wouldn't break binary compatibility in a minor release, if
> this change is to be made it should be done in the next major release
> branch IMO

just want to point out, that this is no change that breaks binary 
compatibility.

bye blackdrag

-- 
Jochen "blackdrag" Theodorou
blog: http://blackdragsview.blogspot.com/


Re: precedence rules for power operator vs -, +, ++, --

Posted by Graeme Rocher <gr...@gmail.com>.
Agreed, I wouldn't break binary compatibility in a minor release, if
this change is to be made it should be done in the next major release
branch IMO

On Mon, Jun 8, 2015 at 3:02 PM, Winnebeck, Jason
<Ja...@windstream.com> wrote:
> If this isn't a clear cut fix then you might want consider leaving it as it is for backwards compatibility. Groovy already has enough issues with breaking changes. At first it looks reasonable that unary - should have precedence over everything but (), but taking the power of a negative number is not normally a sensible thing to do since it only works when the right hand side is an integer and half the time the result is positive. So, in my mind there are arguments for both sides, and then when applied to something as critical as source compatibility, it really lends to keeping existing behavior, in my opinion.
>
> Jason
>
> -----Original Message-----
> From: Paul King [mailto:paulk@asert.com.au]
> Sent: Sunday, June 07, 2015 10:26 AM
> To: users@groovy.incubator.apache.org
> Subject: Re: precedence rules for power operator vs -, +, ++, --
>
>
> OK, looks like there is precedence in both directions:
>
> http://en.wikipedia.org/wiki/Order_of_operations#Exceptions
>
>
> On 7/06/2015 11:48 PM, Jochen Theodorou wrote:
>> "-8 - 1"
>>
>> is in all languages I tests -9. That means Pyhton, Lua, Java, Ruby, QBasic, Javascript, Go. And that in general independent of spacing.
>>
>> bye blackdrag
>>
>> Am 07.06.2015 13:50, schrieb Paul King:
>>>
>>> What do lua/python/ruby return for "-8 - 1"?
>>>
>>> On 7/06/2015 8:40 PM, Jochen Theodorou wrote:
>>>> Am 06.06.2015 13:08, schrieb Paul King:
>>>> [...]
>>>>> def x = 5
>>>>> assert -x ** 2 == -25  // treated as -(x ** 2) assert --x ** 2 ==
>>>>> 24  // treated as --(x ** 2)
>>>>>
>>>>> This behavior is different to the other operators and different to
>>>>> what the comments in the grammar describe as the intended behavior
>>>>> but the order of two rules was presumably accidentally reversed in the grammar.
>>>>>
>>>>> After the change, the following executes:
>>>>>
>>>>> def x = 5
>>>>> assert -x ** 2 == 25   // treated as (-x) ** 2
>>>>> assert --x ** 2 == 16  // treated as (--x) ** 2
>>>>
>>>> I just checked Ruby and Python and there -2**4 will return -16, same
>>>> for -2^4 in Lua. So now I am wondering if that is the right thing
>>>> for unary minus
>>>>
>>>> bye blackdrag
>>>>
>>>
>>>
>>> ---
>>> This email has been checked for viruses by Avast antivirus software.
>>> https://www.avast.com/antivirus
>>>
>>
>>
>
>
> ---
> This email has been checked for viruses by Avast antivirus software.
> https://www.avast.com/antivirus
>
>
> ----------------------------------------------------------------------
> This email message and any attachments are for the sole use of the intended recipient(s). Any unauthorized review, use, disclosure or distribution is prohibited. If you are not the intended recipient, please contact the sender by reply email and destroy all copies of the original message and any attachments.



-- 
Graeme Rocher

RE: precedence rules for power operator vs -, +, ++, --

Posted by "Winnebeck, Jason" <Ja...@windstream.com>.
If this isn't a clear cut fix then you might want consider leaving it as it is for backwards compatibility. Groovy already has enough issues with breaking changes. At first it looks reasonable that unary - should have precedence over everything but (), but taking the power of a negative number is not normally a sensible thing to do since it only works when the right hand side is an integer and half the time the result is positive. So, in my mind there are arguments for both sides, and then when applied to something as critical as source compatibility, it really lends to keeping existing behavior, in my opinion.

Jason

-----Original Message-----
From: Paul King [mailto:paulk@asert.com.au] 
Sent: Sunday, June 07, 2015 10:26 AM
To: users@groovy.incubator.apache.org
Subject: Re: precedence rules for power operator vs -, +, ++, --


OK, looks like there is precedence in both directions:

http://en.wikipedia.org/wiki/Order_of_operations#Exceptions


On 7/06/2015 11:48 PM, Jochen Theodorou wrote:
> "-8 - 1"
>
> is in all languages I tests -9. That means Pyhton, Lua, Java, Ruby, QBasic, Javascript, Go. And that in general independent of spacing.
>
> bye blackdrag
>
> Am 07.06.2015 13:50, schrieb Paul King:
>>
>> What do lua/python/ruby return for "-8 - 1"?
>>
>> On 7/06/2015 8:40 PM, Jochen Theodorou wrote:
>>> Am 06.06.2015 13:08, schrieb Paul King:
>>> [...]
>>>> def x = 5
>>>> assert -x ** 2 == -25  // treated as -(x ** 2) assert --x ** 2 == 
>>>> 24  // treated as --(x ** 2)
>>>>
>>>> This behavior is different to the other operators and different to 
>>>> what the comments in the grammar describe as the intended behavior 
>>>> but the order of two rules was presumably accidentally reversed in the grammar.
>>>>
>>>> After the change, the following executes:
>>>>
>>>> def x = 5
>>>> assert -x ** 2 == 25   // treated as (-x) ** 2
>>>> assert --x ** 2 == 16  // treated as (--x) ** 2
>>>
>>> I just checked Ruby and Python and there -2**4 will return -16, same 
>>> for -2^4 in Lua. So now I am wondering if that is the right thing 
>>> for unary minus
>>>
>>> bye blackdrag
>>>
>>
>>
>> ---
>> This email has been checked for viruses by Avast antivirus software.
>> https://www.avast.com/antivirus
>>
>
>


---
This email has been checked for viruses by Avast antivirus software.
https://www.avast.com/antivirus


----------------------------------------------------------------------
This email message and any attachments are for the sole use of the intended recipient(s). Any unauthorized review, use, disclosure or distribution is prohibited. If you are not the intended recipient, please contact the sender by reply email and destroy all copies of the original message and any attachments.

Re: precedence rules for power operator vs -, +, ++, --

Posted by Paul King <pa...@asert.com.au>.
OK, looks like there is precedence in both directions:

http://en.wikipedia.org/wiki/Order_of_operations#Exceptions


On 7/06/2015 11:48 PM, Jochen Theodorou wrote:
> "-8 - 1"
>
> is in all languages I tests -9. That means Pyhton, Lua, Java, Ruby, QBasic, Javascript, Go. And that in general independent of spacing.
>
> bye blackdrag
>
> Am 07.06.2015 13:50, schrieb Paul King:
>>
>> What do lua/python/ruby return for "-8 - 1"?
>>
>> On 7/06/2015 8:40 PM, Jochen Theodorou wrote:
>>> Am 06.06.2015 13:08, schrieb Paul King:
>>> [...]
>>>> def x = 5
>>>> assert -x ** 2 == -25  // treated as -(x ** 2)
>>>> assert --x ** 2 == 24  // treated as --(x ** 2)
>>>>
>>>> This behavior is different to the other operators and different to what
>>>> the comments in the grammar describe as the intended behavior but the
>>>> order of two rules was presumably accidentally reversed in the grammar.
>>>>
>>>> After the change, the following executes:
>>>>
>>>> def x = 5
>>>> assert -x ** 2 == 25   // treated as (-x) ** 2
>>>> assert --x ** 2 == 16  // treated as (--x) ** 2
>>>
>>> I just checked Ruby and Python and there -2**4 will return -16, same
>>> for -2^4 in Lua. So now I am wondering if that is the right thing for
>>> unary minus
>>>
>>> bye blackdrag
>>>
>>
>>
>> ---
>> This email has been checked for viruses by Avast antivirus software.
>> https://www.avast.com/antivirus
>>
>
>


---
This email has been checked for viruses by Avast antivirus software.
https://www.avast.com/antivirus


Re: precedence rules for power operator vs -, +, ++, --

Posted by Jochen Theodorou <bl...@gmx.org>.
"-8 - 1"

is in all languages I tests -9. That means Pyhton, Lua, Java, Ruby, 
QBasic, Javascript, Go. And that in general independent of spacing.

bye blackdrag

Am 07.06.2015 13:50, schrieb Paul King:
>
> What do lua/python/ruby return for "-8 - 1"?
>
> On 7/06/2015 8:40 PM, Jochen Theodorou wrote:
>> Am 06.06.2015 13:08, schrieb Paul King:
>> [...]
>>> def x = 5
>>> assert -x ** 2 == -25  // treated as -(x ** 2)
>>> assert --x ** 2 == 24  // treated as --(x ** 2)
>>>
>>> This behavior is different to the other operators and different to what
>>> the comments in the grammar describe as the intended behavior but the
>>> order of two rules was presumably accidentally reversed in the grammar.
>>>
>>> After the change, the following executes:
>>>
>>> def x = 5
>>> assert -x ** 2 == 25   // treated as (-x) ** 2
>>> assert --x ** 2 == 16  // treated as (--x) ** 2
>>
>> I just checked Ruby and Python and there -2**4 will return -16, same
>> for -2^4 in Lua. So now I am wondering if that is the right thing for
>> unary minus
>>
>> bye blackdrag
>>
>
>
> ---
> This email has been checked for viruses by Avast antivirus software.
> https://www.avast.com/antivirus
>


-- 
Jochen "blackdrag" Theodorou
blog: http://blackdragsview.blogspot.com/


Re: precedence rules for power operator vs -, +, ++, --

Posted by Paul King <pa...@asert.com.au>.
What do lua/python/ruby return for "-8 - 1"?

On 7/06/2015 8:40 PM, Jochen Theodorou wrote:
> Am 06.06.2015 13:08, schrieb Paul King:
> [...]
>> def x = 5
>> assert -x ** 2 == -25  // treated as -(x ** 2)
>> assert --x ** 2 == 24  // treated as --(x ** 2)
>>
>> This behavior is different to the other operators and different to what
>> the comments in the grammar describe as the intended behavior but the
>> order of two rules was presumably accidentally reversed in the grammar.
>>
>> After the change, the following executes:
>>
>> def x = 5
>> assert -x ** 2 == 25   // treated as (-x) ** 2
>> assert --x ** 2 == 16  // treated as (--x) ** 2
>
> I just checked Ruby and Python and there -2**4 will return -16, same for -2^4 in Lua. So now I am wondering if that is the right thing for unary minus
>
> bye blackdrag
>


---
This email has been checked for viruses by Avast antivirus software.
https://www.avast.com/antivirus


Re: precedence rules for power operator vs -, +, ++, --

Posted by Jochen Theodorou <bl...@gmx.org>.
Am 06.06.2015 13:08, schrieb Paul King:
[...]
> def x = 5
> assert -x ** 2 == -25  // treated as -(x ** 2)
> assert --x ** 2 == 24  // treated as --(x ** 2)
>
> This behavior is different to the other operators and different to what
> the comments in the grammar describe as the intended behavior but the
> order of two rules was presumably accidentally reversed in the grammar.
>
> After the change, the following executes:
>
> def x = 5
> assert -x ** 2 == 25   // treated as (-x) ** 2
> assert --x ** 2 == 16  // treated as (--x) ** 2

I just checked Ruby and Python and there -2**4 will return -16, same for 
-2^4 in Lua. So now I am wondering if that is the right thing for unary 
minus

bye blackdrag

-- 
Jochen "blackdrag" Theodorou
blog: http://blackdragsview.blogspot.com/