On Tue, Jul 7, 2009 at 1:48 AM, Andrei
Alexandrescu<seewebsiteforem...@erdani.org> wrote:
>
> Walter has implemented an ingenious scheme for disallowing narrowing
> conversions while at the same time minimizing the number of casts required.
> He hasn't explained it, so I'll sketch an explanation here.
>
> The basic approach is "value range propagation": each expression is
> associated with a minimum possible value and a maximum possible value. As
> complex expressions are assembled out of simpler expressions, the ranges are
> computed and propagated.
>
> For example, this code compiles:
>
> int x = whatever();
> bool y = x & 1;
>
> The compiler figures that the range of x is int.min to int.max, the range of
> 1 is 1 to 1, and (here's the interesting part), the range of x & 1 is 0 to
> 1. So it lets the code go through. However, it won't allow this:
>
> int x = whatever();
> bool y = x & 2;
>
> because x & 2 has range between 0 and 2, which won't fit in a bool.

Very cool.  :)

> The approach generalizes to arbitrary complex expressions. Now here's the
> trick though: the value range propagation is local, i.e. all ranges are
> forgotten beyond one expression. So as soon as you move on to the next
> statement, the ranges have been forgotten.
>
> Why? Simply put, increased implementation difficulties and increased
> compiler memory footprint for diminishing returns. Both Walter and I noticed
> that expression-level value range propagation gets rid of all dangerous
> cases and the vast majority of required casts. Indeed, his test suite,
> Phobos, and my own codebase required surprisingly few changes with the new
> scheme. Moreover, we both discovered bugs due to the new feature, so we're
> happy with the status quo.

Sounds fairly reasonable.

> Now consider your code:
>
> byte x,y,z;
> z = x+y;
>
> The first line initializes all values to zero. In an intra-procedural value
> range propagation, these zeros would be propagated to the next statement,
> which would range-check. However, in the current approach, the ranges of x,
> y, and z are forgotten at the first semicolon. Then, x+y has range
> -byte.min-byte.min up to byte.max+byte.max as far as the type checker knows.
> That would fit in a short (and by the way I just found a bug with that
> occasion) but not in a byte.

The only thing is: why doesn't _this_ fail, then?

int x, y, z;
z = x + y;

I'm sure it's out of convenience, but what about in ten, fifteen years
when 32-bit architectures are a historical relic and there's still
this hole in the type system?

The same argument applies for the implicit conversions between int and
uint.  If you're going to do that, why not have implicit conversions
between long and ulong on 64-bit platforms?

Reply via email to