http://d.puremagic.com/issues/show_bug.cgi?id=1977





------- Comment #16 from [EMAIL PROTECTED]  2008-11-24 16:55 -------
I searched around, and you are right that C# disallows compiling byte + byte
operands, and it does allow += operands.  The reasons given were not to forbid
reassignment to the same type for fear of overflow (as is obvious by allowing
the += operation), the point is to prevent operation overflow where it is not
expected. for example:

int x = (byte)64 + (byte)64;

should result in x == 128, not x == -128.

And the enforcement is not in the compiler warning system, the enforcement is
that they only define op codes for integer arithmetic, so the compiler promotes
the bytes to integers which result in an integer.

But C++ does not forbid it, at least with g++ (even with -Wall).

This is not to say that the choices C# made are correct, it's just that there
is precedent in C# (couldn't find Java reference, but I'm sure it's the same).

Here is a possible solution that allows current safe behavior and relaxes the
implicit casting rules enough so that overflow is allowed to happen in the
correct situations:

I think everyone agrees that the following:

byte b = 64;
int i = b + b;

should produce i == 128.

And most believe that:

byte b2 = b + b;

should produce b2 == -128 without error, and should be equivalent semantically
to:

byte b2 = b;
b2 += b;

We don't want adding 2 bytes together to result in a byte result in all cases,
only in cases where the actual assignment or usage is to a byte.

What if we defined several 'internal' types that were only used by the
compiler?

pbyte -> byte promoted to an int (represented as an int internally)
pubyte -> ubyte promoted to an int
pshort -> short promoted to an int
pushort -> ushort promoted to an int
etc...

The 'promoted' types internally work just like int except in certain cases:

If you have (px or x) <op> (px or x), the resulting type is px

If you have (px or x) <op> (py or y), or (py or y) <op> (px or x), and the
rules of promotion allow x to be implicitly cast to y, the resulting type is
py.  Otherwise, the resulting type is int.

px is implicitly castable to x.

if the rules of promotion allow x to be implicitly cast to y, px is implicitly
castable to y.
otherwise, assigning px to y requires an explicit cast.

if calling a function foo with argument type px, where foo accepts type x, it
is allowed.

If calling a function foo with argument type px, where foo accepts type y, and
x is implicitly castable to y, it is allowed.  If x is not implicitly castable
to y, it requires a cast.

if a variable is declared with 'auto', and the initializer is of type px, then
the variable is declared as an int.

You can't declare any variables of type pbyte, etc, and the types actually
don't have symbolic names, they are used internally by the compiler.

Now you have correct resolution of homogeneous operations, and no overflow of
data where it is not desired.

examples:

byte b = 64;
b + b -> evaluates to pbyte(128)
b = b + b -> evaluates to b = pbyte(128), results in b == -128
int i = b + b -> evaluates to int i = pbyte(128), results in i == 128.
short s = b + b -> evaultes to short s = pbyte(128), results in s == 128.

short s = 64;
byte b = s + s; -> evaluates to byte b = pshort(128), requires a cast because
short does not fit into byte.

void foo(byte b);
void foo2(short s);

byte x;
short s;
foo(x + x); // allowed
foo2(x + x); // allowed
foo(s + s); // requires cast
foo2(s + s); // allowed 

Does this cover the common cases?  Is there a reason why this can't be
implemented?  Is there a reason why this *shouldn't* be implemented?


-- 

Reply via email to