flagging unsigned subtraction assigned to bigger signed number?

Walter Bright newshound2 at digitalmars.com
Wed May 21 04:44:35 UTC 2025


This is a common issue. Unfortunately, nobody has come up with a solution to 
this in the last 45 years. Since every combination of signed and unsigned has 
well-defined behavior, prohibiting one of those behaviors is going to break a 
lot of code. Changing the conversion rules will break a lot of existing 
behavior. There's no way around it.

There is hope, however. Try the following rules:

1. use `size_t` for all indices and pointer offsets

2. use `ptrdiff_t` for all deltas of the form `size_t - size_t`

Given:
```d
float vpos = 600 - 30 * (messages.length - i);
```
the types are:

```
float = int - int * (size_t - size_t);
```
The rvalue integral promotion rules turn everything into size_t, which is unsigned.

The difficulty arises from `(messages.length - i)` which is computing a delta 
between two `size_t`s being another `size_t`. What you'd like is the result of 
the expression being a `ptrdiff_t`.
```d
ptrdiff_t delta = messages.length - i;
float ypos = 600 - delta;
```
That should give you coherent and robust results. No forced cast is needed. 
(Forced casts should be avoided, as they can hide bugs.)

You could also do this:
```d
foreach_reverse(ptrdiff_t i, v; messages) // messages is a string array
{
     float vpos = 600 - 30 * i;
     DrawText(messages.ptr, 100, vpos.to!int, 20, Colors.WHITE);
}
```
but one could argue it's a bit too clever.

P.S. since size_t is just an alias for uint or ulong, a special status for 
size_t is impractical. So you cannot just say that `size_t - size_t` should be 
typed as `ptrdiff_t`.

P.P.S. Some languages, like Java, decided the solution is to not have an 
unsigned type. This worked until programmers resorted to desperate measures to 
fake an unsigned type.

P.P.P.S. Forced casting results in hidden risk of losing significant bits. Not a 
good plan for robust code.


More information about the Digitalmars-d mailing list