Robert Jacques wrote:
On Tue, 07 Jul 2009 01:48:41 -0400, Andrei Alexandrescu
<[email protected]> wrote:
Robert Jacques wrote:
On Mon, 06 Jul 2009 01:05:10 -0400, Walter Bright
<[email protected]> wrote:
Something for everyone here.
http://www.digitalmars.com/d/1.0/changelog.html
http://ftp.digitalmars.com/dmd.1.046.zip
http://www.digitalmars.com/d/2.0/changelog.html
http://ftp.digitalmars.com/dmd.2.031.zip
Thanks for another great release.
Also, I'm not sure if this is a bug or a feature with regard to the
new integer rules:
byte x,y,z;
z = x+y; // Error: cannot implicitly convert expression
(cast(int)x + cast(int)y) of type int to byte
which makes sense, in that a byte can overflow, but also doesn't
make sense, since integer behaviour is different.
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.
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.
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.
That's really cool. But I don't think that's actually happening (Or are
these the bugs you're talking about?):
byte x,y;
short z;
z = x+y; // Error: cannot implicitly convert expression (cast(int)x
+ cast(int)y) of type int to short
// Repeat for ubyte, bool, char, wchar and *, -, /
http://d.puremagic.com/issues/show_bug.cgi?id=3147 You may want to add
to it.
And by that logic shouldn't the following happen?
int x,y;
int z;
z = x+y; // Error: cannot implicitly convert expression
(cast(long)x + cast(long)y) of type long to int
No. Int remains "special", i.e. arithmetic operations on it don't
automatically grow to become long.
i.e. why the massive inconsistency between byte/short and int/long?
(This is particularly a pain for generic i.e. templated code)
I don't find it a pain. It's a practical decision.
BTW: this means byte and short are not closed under arithmetic
operations, which drastically limit their usefulness.
I think they shouldn't be closed because they overflow for relatively
small values.
Andrei