On 3/17/16 6:46 PM, tsbockman wrote:
On Thursday, 17 March 2016 at 17:09:46 UTC, Steven Schveighoffer wrote:
Converting unsigned to signed or vice versa (of the same size type) is
safe. No information is lost.

Saying that "no information is lost" in such a case, is like saying that
if I encrypt my hard drive and then throw away the password, "no
information is lost". Technically this is true: the bit count is the
same as it was before.

It's hard to throw away the "key" of 2's complement math.

In practice, though, the knowledge of how information is encoded is
essential to actually using it.

In practice, a variable that is unsigned or signed is expected to behave like it is declared. I don't think anyone expects differently.

When I see:

size_t x = -1;

I expect x to behave like an unsigned size_t that represents -1. There is no ambiguity here. Where it gets confusing is if you didn't mean to type size_t. But the compiler can't know that.

When you start doing comparisons, then ambiguity creeps in. The behavior is well defined, but not very intuitive. You can get into trouble even without mixing signed/unsigned types. For example:

for(size_t i = 0; i < a.length - 1; ++i)

This is going to crash when a.length == 0. Better to do this:

for(size_t i = 0; i + 1 < a.length; ++i)

unsigned math can be difficult, there is no doubt. But we can't just disable it, or disable unsigned conversions.

In the same way, using `cast(ulong)` to pass `-1L` to a function that
expects a `ulong` results in a de-facto loss of information, because
that `-1L` can no longer distinguished from `ulong.max`, despite the
fundamental semantic difference between the two.

Any time you cast a type, the original type information is lost. But in this case, no bits are lost. In this case, the function is declaring "I don't care what your original type was, I want to use ulong". If it desires to know the original type, it should use a template parameter instead.

Note, I have made these mistakes myself, and I understand what you are asking for and why you are asking for it. But these are bugs. The user is telling the compiler to do one thing, and expecting it to do something else. It's not difficult to fix, and in fact, many lines of code are written specifically to take advantage of these rules. This is why we cannot remove them. The benefit is not worth the cost.

VRP on steroids would be nice, but I don't think it's as trivial to
solve.

D's current VRP is actually surprisingly anemic: it doesn't even
understand integer comparisons, or the range restrictions implied by the
predicate when a certain branch of an `if` statement is taken.

Lionello Lunesu made a PR a while back that adds these two features, and
it makes the compiler feel a lot smarter. (The PR was not accepted at
the time, but I have since revived it:
     https://github.com/D-Programming-Language/dmd/pull/5229)

I'm not compiler-savvy enough to have an opinion on the PR, but I think more sophisticated VRP would be good.

-Steve

Reply via email to