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