This is a simplified version of some older D code of mine.
The cast is needed to convert int->uint:


uint foo(T)(T x) if (is(T == uint)) {
    uint ans = 0;
    while (x >>= 1)
        ans++;
    return ans;
}
void bar(int x) {
    auto xx = foo(cast(uint)x);
}
void main() {}



I have "improved" it adding a nice "in" in the bar() signature. The code 
compiles and runs still:


uint foo(T)(T x) if (is(T == uint)) {
    uint ans = 0;
    while (x >>= 1)
        ans++;
    return ans;
}
void bar(in int x) {
    auto xx = foo(cast(uint)x);
}
void main() {}


Unfortunately now the code contains a small bug. The cast now converts 
const(int)->uint, and foo() will modify a const value, that gives undefined 
effects in D2.

D1 has only "const" (that is "enum" of D2), so I think a single kind of cast() 
is enough in D1. But D2 has const/immutable too (and other tags) so I think a 
single kind of cast is now a bit short.

If Phobos (or D2 itself) adds a kind of const_cast!(), _and_ the power of D 
cast() is reduced removing its ability to remove attributes like 
const/immutable from a type, the bug I have created doesn't happen, but it 
looks a bit messy:

const(int) x;
auto y = cast(uint)x;
static assert(is(typeof(y) == const(uint)));
auto z = const_cast!uint(x);
static assert(is(typeof(z) == uint));


What do you think?

A cast means punching a hole in the type system, so the programmer has to use 
it with care. The problems are born from the programmer not having a complete 
knowledge of the situation (the types involved) when he/she uses the cast, or 
as in this case when I have later modified the code.

The example shown in this post is only the last one I have found. Casts now and 
then cause me small troubles.

This is not the first time we discuss about casts, and probably it isn't the 
last one :-)

Bye,
bearophile

Reply via email to