Treating the abusive unsigned syndrome

Andrei Alexandrescu SeeWebsiteForEmail at erdani.org
Wed Nov 26 07:12:12 PST 2008


Don wrote:
> Andrei Alexandrescu wrote:
>> D pursues compatibility with C and C++ in the following manner: if a 
>> code snippet compiles in both C and D or C++ and D, then it should 
>> have the same semantics.
>>
>> A classic problem with C and C++ integer arithmetic is that any 
>> operation involving at least an unsigned integral receives 
>> automatically an unsigned type, regardless of how silly that actually 
>> is, semantically. About the only advantage of this rule is that it's 
>> simple. IMHO it only has disadvantages from then on.
>>
>> The following operations suffer from the "abusive unsigned syndrome" 
>> (u is an unsigned integral, i is a signed integral):
>>
>> (1) u + i, i + u
>> (2) u - i, i - u
>> (3) u - u
>> (4) u * i, i * u, u / i, i / u, u % i, i % u (compatibility with C 
>> requires that these all return unsigned, ouch)
>> (5) u < i, i < u, u <= i etc. (all ordering comparisons)
>> (6) -u
> 
> I think that most of these problems are caused by C enforcing a foolish 
> consitency between literals and variables.
> The idea that literals like '0' and '1' are of type int is absurd, and 
> has caused a torrent of problems. '0' is just '0'.
> 
> uint a = 1;
> does NOT contain an 'implicit conversion from int to uint', any more 
> than there are implicit conversions from naturals to integers in 
> mathematics. So I really like the polysemous types idea.

Yah, polysemy will take care of the constants. It's also rather easy to 
implement for them.

> For example, when is it reasonable to use -u?
> It's useful with literals like
> uint a = -1u; which is equivalent to uint a = 0xFFFF_FFFF.
> Anywhere else, it's probably a bug.

Maybe not even for constants as all uses of -u can be easily converted 
in ~u + 1. I'd gladly agree to disallow -u entirely.

> My suspicion is, that if you allowed all signed-unsigned operations when 
> at least one was a literal, and made everything else illegal, you'd fix 
> most of the problems. In particular, there'd be a big reduction in 
> people abusing 'uint' as a primitive range-limited int.

Well, part of my attempt is to transform that abuse into legit use. In 
other words, I do want to allow people to consider uint a reasonable 
model of natural numbers. It can't be perfect, but I believe we can make 
it reasonable.

Notice that the fact that one operand is a literal does not solve all of 
the problems I mentioned. There is for example no progress in typing u1 
- u2 appropriately.

> Although it would be nice to have a type which was range-limited, 'uint' 
> doesn't do it. Instead, it guarantees the number is between 0 and 
> int.max*2+1 inclusive. Allowing mixed operations encourages programmers 
> to focus the benefit of 'the lower bound is zero!' while forgetting that 
> there is an enormous downside ('I'm saying that this could be larger 
> than int.max!')

I'm not sure I understand this part. To me, the larger problem is 
underflow, e.g. when subtracting two small uints results in a large uint.

> Interestingly, none of these problems exist in assembly language 
> programming, where every arithmetic instruction affects the overflow 
> flag (for signed operations) as well as the carry flag (for unsigned).

They do exist. You need to use imul/idiv vs. mul/div depending on what 
signedness your operators have.


Andrei



More information about the Digitalmars-d mailing list