November 05, 2015 Re: Preventing implicit conversion | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dominikus Dittes Scherkl | And I want to have small number litterals automatically choosing the smallest fitting type. If I write ubyte b = 1u; auto c = b + 1u; I expect the 1u to be of type ubyte - and also c. |
November 05, 2015 Re: Preventing implicit conversion | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dominikus Dittes Scherkl | On Thursday, 5 November 2015 at 10:07:30 UTC, Dominikus Dittes Scherkl wrote: > And I want to have small number litterals automatically choosing the smallest fitting type. It does, that's the value range propagation at work. Inside one expression, if the compiler can prove it fits in a smaller type, the explicit cast is not necessary. ubyte a = 255; // allowed, despite 255 being an int literal ubyte b = 253L + 2L; // allowed, though I used longs there ubyte c = 255 + 1; // disallowed, 256 doesn't fit However, the key there was "in a single expression". If you break it into multiple lines with runtime values, the compiler assumes the worst: int i = 254; int i2 = 1; ubyte a2 = i + i2; // won't work because it doesn't realize the values But, adding some constant operation can narrow it back down: ubyte a3 = (i + i2) & 0xff; // but this does because it knows anything & 0xff will always fit in a byte > ubyte b = 1u; > auto c = b + 1u; > > I expect the 1u to be of type ubyte - and also c. This won't work because of the one-expression rule. In the second line, it doesn't know for sure what b is, it just knows it is somewhere between 0 and 255. So it assumes the worst, that it is 255, and you add one, giving 256... which doesn't fit in a byte. It requires the explicit cast or a &0xff or something like that to make the bit truncation explicit. I agree this can be kinda obnoxious (and I think kinda pointless if you're dealing with explicitly typed smaller things throughout) but knowing what it is actually doing can help a little. |
November 05, 2015 Re: Preventing implicit conversion | ||||
---|---|---|---|---|
| ||||
Posted in reply to Adam D. Ruppe | On Thursday, 5 November 2015 at 13:23:34 UTC, Adam D. Ruppe wrote: > On Thursday, 5 November 2015 at 10:07:30 UTC, Dominikus Dittes Scherkl wrote: >> ubyte b = 1u; >> auto c = b + 1u; >> >> I expect the 1u to be of type ubyte - and also c. > > This won't work because of the one-expression rule. In the second line, it doesn't know for sure what b is, it just knows it is somewhere between 0 and 255. So it assumes the worst, that it is 255, and you add one, giving 256... which doesn't fit in a byte. That would be fine - but c is not ushort (which the worst-case 256 would fit in), not even uint, but int! A signed type! Just because of the crazy C interger propagation rules! And, ok, one needs to accept that auto may not do exactly what I wish for, but if I give an exact type that is likely to fit (and has to if all operands are of the same type), I expect it to work without extra casts: ubyte d = b + 1u; // doesn't compile ubyte d = b + (ubyte)1; // works - and overflows to 0 if b is 255 |
November 05, 2015 Re: Preventing implicit conversion | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dominikus Dittes Scherkl | On Thursday, 5 November 2015 at 22:15:46 UTC, Dominikus Dittes Scherkl wrote: > On Thursday, 5 November 2015 at 13:23:34 UTC, Adam D. Ruppe wrote: >> On Thursday, 5 November 2015 at 10:07:30 UTC, Dominikus Dittes Scherkl wrote: > ubyte d = b + (ubyte)1; Sorry, should of course be: ubyte d = b + ubyte(1); Too much C lately :-/ |
November 06, 2015 Re: Preventing implicit conversion | ||||
---|---|---|---|---|
| ||||
Posted in reply to ixid | On Thursday, November 05, 2015 09:33:39 ixid via Digitalmars-d-learn wrote:
> In C++ I can add two shorts together without having to use a cast to assign the result to one of the two shorts. It just seems super clunky not to be able to do basic operations on basic types without casts everywhere.
That's why we have value range propagation - so that when the compiler can prove that the result will fit in the smaller type, it'll let you assign to it. Perhaps the compiler should do more with that than it currently does, but it's definitely help reduce the number of casts that are required for narrowing conversions.
But allowing implicit narrowing conversions is a source of bugs, which is why languages like D, C#, and Java have all made narrowing conversions illegal without a cast. Yes, that can be annoying when you need to do math on a byte or short, and you want the result to end up in a byte or short, but it prevents bugs. It's a tradeoff. Fortunately, VPR improves the situation, but we're not going to be able to prevent narrowing bugs while still allowing implicit narrowing conversions. C/C++ went the route that requires fewer casts but more easily introduces bugs, whereas D, Java, and C# went the route where it's harder to introduce bugs but doing arithmetic on types smaller than int gets a bit annoying. Personally, I think that the route that D has taken is the better one, but it is a matter of opinion and priorities.
But if it's important enough to you to not need to cast for arithmetic operations on small integer types, you can always create a wrapper type that does all of the casts for you so that you get the implicit conversions.
- Jonathan M Davis
|
Copyright © 1999-2021 by the D Language Foundation