Thread overview
What is this behavior and how do I disable or get around it?
Sep 05, 2016
pineapple
Sep 05, 2016
ak
Sep 05, 2016
Mike Parker
Sep 05, 2016
Jonathan M Davis
September 05, 2016
This program does not compile.

Error: cannot implicitly convert expression (cast(int)x - cast(int)x) of type int to ubyte

    void main(){
        ubyte x;
        x = x - x;
    }

I don't even know what to say. Who thought this behavior was a good idea?

September 05, 2016
On Monday, 5 September 2016 at 00:26:01 UTC, pineapple wrote:
> This program does not compile.
>
> Error: cannot implicitly convert expression (cast(int)x - cast(int)x) of type int to ubyte
>
>     void main(){
>         ubyte x;
>         x = x - x;
>     }
>
> I don't even know what to say. Who thought this behavior was a good idea?

x = cast(ubyte)(x - x);
September 05, 2016
On Monday, 5 September 2016 at 00:26:01 UTC, pineapple wrote:
> This program does not compile.
>
> Error: cannot implicitly convert expression (cast(int)x - cast(int)x) of type int to ubyte
>
>     void main(){
>         ubyte x;
>         x = x - x;
>     }
>
> I don't even know what to say. Who thought this behavior was a good idea?

See the sections 'Integer Promotions' and 'Usual Arithmetic Conversions' in the docs at [1].

[1] http://dlang.org/spec/type.html#integer-promotions

September 04, 2016
On Monday, September 05, 2016 00:26:01 pineapple via Digitalmars-d-learn wrote:
> This program does not compile.
>
> Error: cannot implicitly convert expression (cast(int)x -
> cast(int)x) of type int to ubyte
>
>      void main(){
>          ubyte x;
>          x = x - x;
>      }
>
> I don't even know what to say. Who thought this behavior was a good idea?

It's exactly the same behavior you get in C/C++ except that they allowing narrowing conversions without a cast, whereas D does not. All arithmetic for integral types smaller than int are done as int. So, the result of x - x is int. And in C/C++, you could happily assign it back to x without realizing that the arithmetic had been done as int, but because D disallows narrowing conversions without a cast (just like C# and Java do), assigning it back then results in an error. And yes, it can be annoying, but it helps catch bugs.

Fortunately, D has VRP (Value Range Propagation), which means that if the compiler can determine that the result of an arithmetic operation would definitely fit in the type that it's assigned to, then there is no error even if it involves a narrowing conversion. So, something like

ubyte x = 19 + 7;

will compile. Unfortunately, the compiler only looks at the current expression rather than doing true control flow analysis when in does VRP. So, something like

ubyte x = 19;
ubyte y = x + 7;

won't compile without adding a cast to the second line, and in practice, I don't think that VRP helps much. It's still better than nothing though, and at some point, it may be expanded to cover multiple statements.

Ultimately, this is just one of those annoyances that comes as a side effect of the compiler trying to prevent a certain class of bugs - in this case, requiring that narrowing conversions use a cast.

- Jonathan M Davis