Casts
Oskar Linde
oskar.lindeREM at OVEgmail.com
Thu Jun 21 03:34:12 PDT 2007
Don Clugston skrev:
> Walter Bright wrote:
>> Don Clugston wrote:
>>> Walter Bright wrote:
>>>> With D, you can cast away const-ness, that is legal. But if you
>>>> subsequently modify the underlying data, that is undefined behavior.
>>>
>>> It sounds that in D, it will be too easy to cast away constness
>>> accidentally.
>>> With C++, at least you can grep for const_cast and detect potentially
>>> dangerous code, and you get a strong visual clue.
>>> Suppose I've written a D function like this:
>>>
>>> void f(int *b, uint c)
>>> {
>>> // maybe I'm avoiding a compiler warning or something.
>>> uint *d = cast(uint *)b;
>>> d += c;
>>> }
>>>
>>> Months later, I'm refactoring the code, and I convert the int *
>>> parameter to an invariant, without recognising that it's changing the
>>> value of b. Oops.
>>>
>>> C++'s const would catch this mistake, but if I understand correctly,
>>> D will compile it without error. Suddenly the function has moved into
>>> the realm of undefined behaviour.
>>>
>>> I hope I'm wrong. Or did I miss something?
>>
>> No, you're not missing something. It is a general problem with cast -
>> cast is a blunt instrument which can easily hide problems.
>
> This means that cast() has just become even more unsafe. So for 2.0, it
> will be even more important to provide ways to avoid usage of cast().
> The .ptr, .re, and .im properties were a huge help; maybe the idea can
> be extended to other cases where a cast is perfectly safe.
I had look at the places I use casts in some of my projects, and found
some categories (in no particular order):
1. Cast needed by the archaic typeinfo system, example:
class C {
int opCmp(Object o) { auto c = cast(C) o; assert(c !is null); ... }
}
typeid(char[]).compare(cast(void *) &str1, cast(void *) &str2);
2. casts from void[], void*
3. Unsigned/signed casts and working around stupid promotion rules:
template T(int n) { ... }
uint n = ...;
T!(cast(int) n) // cast required
// Spot the bug # 1
double randomDelta() {
return (rand() % 3) - 1;
}
// spot the bug #2
void fun(int[] arr) {
long d = arr.length - 10;
while (d > 0)
arr[--d] = 0;
}
4. casts to subclasses (c++ dynamic_cast) (personally very seldom used)
5. casts needed for overload resolution:
std.math.pow(cast(real) doubleVar, intVar); // sigh
6. rational -> floating point
cast(double) a.length / b.length
I can't really see how most of those casts can go away (except #1). If D
got something like generic method injection, one could replace
cast(double) intVar
with
intVar.toDouble, or intVar.to!(double)
but is that any better?
/Oskar
More information about the Digitalmars-d
mailing list