Consider the following C++ program:
-----
#include <cstdio>
int main()
{
signed char c = -128;
printf("%d\n", (int)(-c));
return 0;
}
-----
This prints "128".
Consider the supposedly identical D code:
-----
import core.stdc.stdio;
void main()
{
byte c = -128;
printf("%d\n", cast(int)(-c)); // -128
}
-----
Since the D unary minus doesn't promote byte to int, it yields a different result.
This is a real case that costed ketmar 40 min, while porting working C code.
Porting to D silently broke the code due to subtly different integer promotion rules. I'm pretty sure I would have given up becasue code that is translated is often enough not understood yet.
After investigation:
* Taking the unary minus of byte and short and then asting to int yield different results for the lowest values: -128 and -32768
* Taking the unary minus of ubyte and ushort and then casting to int
yield different results for any value except 0
Why are the promotion rules for unary + and - different from C?
Comment #1 by aliloko — 2016-12-21T00:32:04Z
Created attachment 1626
Patch in ketmar DMD fork ("aliced") to make unary +/- on small integers a warning
Comment #2 by ketmar — 2016-12-21T04:58:18Z
Created attachment 1627
warning on unary minus/plus
fixed patch, made against vanilla. it will show warning for unary -/+ for (u)byte and (u)short, but one can silence that with `-(expr)`. it prolly needs better message with explanation of what it is, and what to do, and why -- but i leave that for that one who will make a PR out of the patch.
Comment #3 by ketmar — 2016-12-21T05:02:24Z
as for the question: promotion rules are what they are currently to allow this:
byte n;
n = -n;
if unary minus will promote `n`, you will need to add `cast` there. and negate never ever drop bits from integer (even byte.min is essentially unchanged, so no info is lost), so it is -- relatively -- safe to not promote here.
Comment #4 by ketmar — 2016-12-21T05:03:34Z
p.s.: i'm not that smart, tbh, i understood the rationale behind the design after alot of hard thinking.