www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - New integer promotion rules

reply rumbu <rumbu rumbu.ro> writes:
This started in the last DMD version (2.078):

byte b = -10;
ulong u = b < 0 ? -b : b;

//Deprecation: integral promotion not done for `-b`, use 
'-transition=intpromote' switch or `-cast(int)(b)

Why do I need a to promote a byte to int to obtain an ulong? Even 
in the extreme case where b is byte.min, -byte.min as unsigned is 
exactly what i need: 128;

This leads to more cases:

ubyte u = cast(ubyte)-b;
//Deprecation: integral promotion not done for `-b`, use 
'-transition=intpromote' switch or `-cast(int)(b)`

Last time I checked, casting is somehow synonym with "I know what 
I'm doing", why do I need another cast to prove my sanity: ubyte 
u = cast(ubyte)-cast(int)b;






		
Jan 17
next sibling parent reply ag0aep6g <anonymous example.com> writes:
On 01/17/2018 08:40 PM, rumbu wrote:
 This started in the last DMD version (2.078):
 
 byte b = -10;
 ulong u = b < 0 ? -b : b;
 
 //Deprecation: integral promotion not done for `-b`, use 
 '-transition=intpromote' switch or `-cast(int)(b)
 
 Why do I need a to promote a byte to int to obtain an ulong? Even in the 
 extreme case where b is byte.min, -byte.min as unsigned is exactly what 
 i need: 128;
Actually, for b = byte.min, you get u = 18446744073709551488. 2.078 is starting to fix this so that you get 128. But that's a breaking change, so you have to use the compiler switch or the cast for a couple releases. In the changelog: https://dlang.org/changelog/2.078.0.html#fix16997
Jan 17
parent reply rumbu <rumbu rumbu.ro> writes:
On Wednesday, 17 January 2018 at 19:54:50 UTC, ag0aep6g wrote:
 On 01/17/2018 08:40 PM, rumbu wrote:
 This started in the last DMD version (2.078):
 
 byte b = -10;
 ulong u = b < 0 ? -b : b;
 
 //Deprecation: integral promotion not done for `-b`, use 
 '-transition=intpromote' switch or `-cast(int)(b)
 
 Why do I need a to promote a byte to int to obtain an ulong? 
 Even in the extreme case where b is byte.min, -byte.min as 
 unsigned is exactly what i need: 128;
Actually, for b = byte.min, you get u = 18446744073709551488.
Wrong, compiled with 2.077 or 2.078 with -transition=intpromote byte b = byte.min; ulong u = -b; writeln(u); outputs correctly 128
 2.078 is starting to fix this so that you get 128. But that's a 
 breaking change, so you have to use the compiler switch or the 
 cast for a couple releases.

 In the changelog: 
 https://dlang.org/changelog/2.078.0.html#fix16997
Jan 17
parent reply rumbu <rumbu rumbu.ro> writes:
And here is why is bothering me:

auto max = isNegative ? cast(Unsigned!T)(-T.min) : 
cast(Unsigned!T)T.max);

The generic code above (which worked for all signed integral 
types T in 2.077) must be rewritten like this in 2.078:

static if (T.sizeof >= 4)
    auto max = isNegative ? cast(Unsigned!T)(-T.min) : 
cast(Unsigned!T)T.max;
else
    auto max = isNegative ? cast(Unsigned!T)(-cast(int)T.min) : 
cast(Unsigned!T)T.max;

Now I have to translate an 1-liner in a 4-liner all around my 
project.
Jan 17
next sibling parent Basile B. <b2.temp gmx.com> writes:
On Wednesday, 17 January 2018 at 20:30:07 UTC, rumbu wrote:
 And here is why is bothering me:

 auto max = isNegative ? cast(Unsigned!T)(-T.min) : 
 cast(Unsigned!T)T.max);

 The generic code above (which worked for all signed integral 
 types T in 2.077) must be rewritten like this in 2.078:

 static if (T.sizeof >= 4)
    auto max = isNegative ? cast(Unsigned!T)(-T.min) : 
 cast(Unsigned!T)T.max;
 else
    auto max = isNegative ? cast(Unsigned!T)(-cast(int)T.min) : 
 cast(Unsigned!T)T.max;

 Now I have to translate an 1-liner in a 4-liner all around my 
 project.
Yes i know. In a way i agree but in another i've accepted the thing, that's why for example there's: https://github.com/dlang/phobos/pull/5958/files I had to do similar things in my own stuff. Other people had to as well. In my stuff i've used `cast(ubyte) (stuff * -1)` instead of `-stuff` because i've verified that in both cases an asm NEG is generated. But well, i understand your concern ;)
Jan 17
prev sibling next sibling parent ag0aep6g <anonymous example.com> writes:
On 01/17/2018 09:30 PM, rumbu wrote:
 And here is why is bothering me:
 
 auto max = isNegative ? cast(Unsigned!T)(-T.min) : cast(Unsigned!T)T.max);
 
 The generic code above (which worked for all signed integral types T in 
 2.077) must be rewritten like this in 2.078:
 
 static if (T.sizeof >= 4)
     auto max = isNegative ? cast(Unsigned!T)(-T.min) : 
 cast(Unsigned!T)T.max;
 else
     auto max = isNegative ? cast(Unsigned!T)(-cast(int)T.min) : 
 cast(Unsigned!T)T.max;
 
 Now I have to translate an 1-liner in a 4-liner all around my project.
So here you prefer the old behavior. But in your previous post you wrote:
 compiled with 2.077 or 2.078 with -transition=intpromote
 
 byte b = byte.min;
 ulong u = -b;
 writeln(u);
 
 outputs correctly 128 
And that's the new behavior. You can't have both. You either get to keep the shorter version of your max code, or you get "correct" results on `ulong u = -b;`. Except you can actually (almost) keep your max code, as far as I see. Under the old rules `-T.min` is just `T.min` again. So you can just drop the negation there and get the same result. And then it works under the new rules too, because there's no negation involved. I.e.: auto max = isNegative ? cast(Unsigned!T)(T.min) : cast(Unsigned!T)T.max;
Jan 17
prev sibling parent reply Rubn <where is.this> writes:
On Wednesday, 17 January 2018 at 20:30:07 UTC, rumbu wrote:
 And here is why is bothering me:

 auto max = isNegative ? cast(Unsigned!T)(-T.min) : 
 cast(Unsigned!T)T.max);

 The generic code above (which worked for all signed integral 
 types T in 2.077) must be rewritten like this in 2.078:

 static if (T.sizeof >= 4)
    auto max = isNegative ? cast(Unsigned!T)(-T.min) : 
 cast(Unsigned!T)T.max;
 else
    auto max = isNegative ? cast(Unsigned!T)(-cast(int)T.min) : 
 cast(Unsigned!T)T.max;

 Now I have to translate an 1-liner in a 4-liner all around my 
 project.
Or write some wrapper code, which you prob should have done in the first place if you use that all around your project: auto max = myMaxFunc!(isNegative, T);
Jan 17
parent reply rumbu <rumbu rumbu.ro> writes:
On Wednesday, 17 January 2018 at 21:12:07 UTC, Rubn wrote:
 On Wednesday, 17 January 2018 at 20:30:07 UTC, rumbu wrote:
 And here is why is bothering me:

 auto max = isNegative ? cast(Unsigned!T)(-T.min) : 
 cast(Unsigned!T)T.max);

 The generic code above (which worked for all signed integral 
 types T in 2.077) must be rewritten like this in 2.078:

 static if (T.sizeof >= 4)
    auto max = isNegative ? cast(Unsigned!T)(-T.min) : 
 cast(Unsigned!T)T.max;
 else
    auto max = isNegative ? cast(Unsigned!T)(-cast(int)T.min) : 
 cast(Unsigned!T)T.max;

 Now I have to translate an 1-liner in a 4-liner all around my 
 project.
Or write some wrapper code, which you prob should have done in the first place if you use that all around your project: auto max = myMaxFunc!(isNegative, T);
"max" was just an over-templated example to highlight the problem, code like "m = n < 0 ? -n : n" doesn't worth a wrapper, for example. But the original questions remain: 1. Why do I need explicitely to promote my byte to int in order to assign it to an ulong? 2.077: ulong u = -b; 2.088: ulong u = -cast(int)b; 2. Why do I need a cast(int) to assign a byte to an ubyte, since I'm explicitely cast it? 2.077: ubyte c = cast(ubyte)-b; 2.088: ubyte c = cast(ubyte)-cast(int)b
Jan 17
next sibling parent ag0aep6g <anonymous example.com> writes:
On 01/17/2018 11:30 PM, rumbu wrote:
 1. Why do I need explicitely to promote my byte to int in order to 
 assign it to an ulong?
 2.077: ulong u = -b; 2.088: ulong u = -cast(int)b;
Those two snippets are not equivalent. When b = byte.min, the 2.077 snippet gives u = 18446744073709551488, while the 2.078 snippet gives u = 128 even when compiled with 2.077. Old code may rely on u = 18446744073709551488, and that's why dmd 2.078 doesn't just silently give you 128. Instead you have to use the cast or the compiler switch to tell dmd that you actually want the new behavior. In the future, the new behavior is going to become the default. You have to be explicit about this so that dmd doesn't break your code without you noticing.
 2. Why do I need a cast(int) to assign a byte to an ubyte, since I'm 
 explicitely cast it?
 2.077: ubyte c = cast(ubyte)-b; 2.088: ubyte c = cast(ubyte)-cast(int)b
As above, when b = byte(-128), then `-b` is going to change from byte(-128) to int(128). In this case, that doesn't affect the result, because `cast(ubyte) byte(-128)` and `cast(ubyte) int(128)` are both 128. But the compiler obviously doesn't look that far. And it's not possible for the compiler to analyse the whole program before giving you the deprecation message.
Jan 17
prev sibling next sibling parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 01/17/2018 02:30 PM, rumbu wrote:

 1. Why do I need explicitely to promote my byte to int in order to
 assign it to an ulong?
 2.077: ulong u = -b; 2.088: ulong u = -cast(int)b;
You're not assigning your byte to ulong; you're assigning the expression -b to ulong. -b is discovered to have unintended behavior, which is now fixed. We have to go throught a transition period not to break old code that may have depended on the old unintended behavior.
 2. Why do I need a cast(int) to assign a byte to an ubyte, since I'm
 explicitely cast it?
 2.077: ubyte c = cast(ubyte)-b; 2.088: ubyte c = cast(ubyte)-cast(int)b
Same issue: the question is about what -b means before your cast in the 2.077 version of the code. Ali
Jan 17
prev sibling parent reply Rubn <where is.this> writes:
On Wednesday, 17 January 2018 at 22:30:11 UTC, rumbu wrote:
 code like "m = n < 0 ? -n : n" doesn't worth a wrapper
That code is worth a wrapper, it's called "abs"... m = abs(n);
Jan 17
parent reply rumbu <rumbu rumbu.ro> writes:
On Thursday, 18 January 2018 at 02:30:17 UTC, Rubn wrote:
 On Wednesday, 17 January 2018 at 22:30:11 UTC, rumbu wrote:
 code like "m = n < 0 ? -n : n" doesn't worth a wrapper
That code is worth a wrapper, it's called "abs"... m = abs(n);
Well, since I'm in the learn forum and you seem to have a response to anything, can you help me translate this line under the new integer promotion rules? https://github.com/rumbu13/decimal/blob/master/src/decimal/decimal.d#L7804 Thanks.
Jan 17
parent reply Dominikus Dittes Scherkl <dominikus.scherkl continental-corporation.com> writes:
On Thursday, 18 January 2018 at 06:05:08 UTC, rumbu wrote:
 On Thursday, 18 January 2018 at 02:30:17 UTC, Rubn wrote:
 On Wednesday, 17 January 2018 at 22:30:11 UTC, rumbu wrote:
 code like "m = n < 0 ? -n : n" doesn't worth a wrapper
That code is worth a wrapper, it's called "abs"... m = abs(n);
Well, since I'm in the learn forum and you seem to have a response to anything, can you help me translate this line under the new integer promotion rules? https://github.com/rumbu13/decimal/blob/master/src/decimal/decimal.d#L7804 Thanks.
target = isNegative ? cast(Unsigned!T)(-c) : cast(Unsigned!T)c; That would have been better even before the change, because the operator '-' used on unsigned types is likely to produce unexpected results, if the behaviour is defined at all.
Jan 18
parent reply rumbu <rumbu rumbu.ro> writes:
On Thursday, 18 January 2018 at 12:51:48 UTC, Dominikus Dittes 
Scherkl wrote:
 On Thursday, 18 January 2018 at 06:05:08 UTC, rumbu wrote:
 On Thursday, 18 January 2018 at 02:30:17 UTC, Rubn wrote:
 On Wednesday, 17 January 2018 at 22:30:11 UTC, rumbu wrote:
 code like "m = n < 0 ? -n : n" doesn't worth a wrapper
That code is worth a wrapper, it's called "abs"... m = abs(n);
Well, since I'm in the learn forum and you seem to have a response to anything, can you help me translate this line under the new integer promotion rules? https://github.com/rumbu13/decimal/blob/master/src/decimal/decimal.d#L7804 Thanks.
target = isNegative ? cast(Unsigned!T)(-c) : cast(Unsigned!T)c; That would have been better even before the change, because the operator '-' used on unsigned types is likely to produce unexpected results, if the behaviour is defined at all.
I don't think so: ulong c = 128; bool isNegative = true; byte target = isNegative ? -cast(ubyte)c : cast(ubyte)c; Error Deprecation: integral promotion not done for `-cast(ubyte)c`, use '-transition=intpromote' switch or `-cast(int)(cast(ubyte)c)`
Jan 18
parent reply rumbu <rumbu rumbu.ro> writes:
On Thursday, 18 January 2018 at 17:54:59 UTC, rumbu wrote:
 On Thursday, 18 January 2018 at 12:51:48 UTC, Dominikus Dittes
 target = isNegative ? cast(Unsigned!T)(-c) : cast(Unsigned!T)c;

 That would have been better even before the change, because 
 the operator '-' used on unsigned types is likely to produce 
 unexpected results, if the behaviour is defined at all.
I don't think so: ulong c = 128; bool isNegative = true; byte target = isNegative ? -cast(ubyte)c : cast(ubyte)c; Error Deprecation: integral promotion not done for `-cast(ubyte)c`, use '-transition=intpromote' switch or `-cast(int)(cast(ubyte)c)`
My bad, it works. Thanks: ulong c = 128; bool isNegative = true; byte target = isNegative ? cast(ubyte)-c : cast(ubyte)c;
Jan 18
parent rumbu <rumbu rumbu.ro> writes:
On Thursday, 18 January 2018 at 18:00:51 UTC, rumbu wrote:
 On Thursday, 18 January 2018 at 17:54:59 UTC, rumbu wrote:
 On Thursday, 18 January 2018 at 12:51:48 UTC, Dominikus Dittes
 target = isNegative ? cast(Unsigned!T)(-c) : 
 cast(Unsigned!T)c;

 That would have been better even before the change, because 
 the operator '-' used on unsigned types is likely to produce 
 unexpected results, if the behaviour is defined at all.
I don't think so: ulong c = 128; bool isNegative = true; byte target = isNegative ? -cast(ubyte)c : cast(ubyte)c; Error Deprecation: integral promotion not done for `-cast(ubyte)c`, use '-transition=intpromote' switch or `-cast(int)(cast(ubyte)c)`
My bad, it works. Thanks: ulong c = 128; bool isNegative = true; byte target = isNegative ? cast(ubyte)-c : cast(ubyte)c;
But this doesn't: ushort c = 128; bool isNegative = true; byte target = isNegative ? cast(ubyte)-c : cast(ubyte)c; Error Deprecation: integral promotion not done for `-c`, use '-transition=intpromote' switch or `-cast(int)(c) This is starting to become truly crazy.
Jan 18
prev sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 1/17/18 2:40 PM, rumbu wrote:
 This started in the last DMD version (2.078):
 
 byte b = -10;
 ulong u = b < 0 ? -b : b;
 
 //Deprecation: integral promotion not done for `-b`, use 
 '-transition=intpromote' switch or `-cast(int)(b)
 
 Why do I need a to promote a byte to int to obtain an ulong? Even in the 
 extreme case where b is byte.min, -byte.min as unsigned is exactly what 
 i need: 128;
 
 This leads to more cases:
 
 ubyte u = cast(ubyte)-b;
 //Deprecation: integral promotion not done for `-b`, use 
 '-transition=intpromote' switch or `-cast(int)(b)`
 
 Last time I checked, casting is somehow synonym with "I know what I'm 
 doing", why do I need another cast to prove my sanity: ubyte u = 
 cast(ubyte)-cast(int)b;
I was going to respond with a helpful guide on what to do here, but I either misunderstand the docs, or I don't agree with the transition requirements. I thought that you could simply ignore this deprecation message if it doesn't affect you (i.e. you don't have the possibility of seeing the corner cases that are fixed), but looking at the changelog it says: "Once deprecated this will become an error, and then the C-like behavior will become the default." So this says, even if you aren't affected, you *still* have to add casts to avoid a future error? I thought it was going to be deprecated, and then after some number of versions it would just be switched to the new behavior. Is there going to be a point where casts aren't needed? Otherwise, this is pretty ugly. -Steve
Jan 18
parent reply ag0aep6g <anonymous example.com> writes:
On 01/18/2018 03:30 PM, Steven Schveighoffer wrote:
 Is there going to be a point where casts aren't needed? Otherwise, this 
 is pretty ugly.
You don't need casts when you use `-transition=intpromote`.
Jan 18
parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 1/18/18 11:14 AM, ag0aep6g wrote:
 On 01/18/2018 03:30 PM, Steven Schveighoffer wrote:
 Is there going to be a point where casts aren't needed? Otherwise, 
 this is pretty ugly.
You don't need casts when you use `-transition=intpromote`.
Sure, but what does the statement "Once deprecated this will become an error" mean? Will I have to use the -transition=intpromote switch forever to avoid an error? Thinking about the fact that the deprecation doesn't show an error for the -transition switch, makes me think possibly the changelog message is incorrect. -Steve
Jan 18
parent ag0aep6g <anonymous example.com> writes:
On 01/18/2018 05:22 PM, Steven Schveighoffer wrote:
 Sure, but what does the statement "Once deprecated this will become an 
 error" mean? Will I have to use the -transition=intpromote switch 
 forever to avoid an error?
As you quoted before: "Once deprecated this will become an error, and then the C-like behavior will become the default." I'm interpreting that to mean that it will become an error for some time, but later it will be allowed again with the new behavior. And then you can throw away `-transition=intpromote`.
Jan 18