View mode: basic / threaded / horizontal-split · Log in · Help
June 21, 2007
Re: D2.0: an example of use-case for casting invariant away
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.
June 21, 2007
Re: D2.0: an example of use-case for casting invariant away
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.

Usage of invariants inside unions is suspect too.
At least where some members are invariant and others are not const, it's asking 
for trouble -- cast() by stealth.

union U {
 invariant C *c;
 C *d;
}
Though arguably unions are always a blunt, dangerous instrument as well.
June 21, 2007
Re: D2.0: an example of use-case for casting invariant away
On Thu, 21 Jun 2007 11:32:53 +0400, Walter Bright  
<newshound1@digitalmars.com> wrote:

> Don Clugston wrote:
>> 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.

May be it is better to define two new cast operators: const_cast, that  
removes only const, and invariant_cast, that removes only invariant.  
Ordinal cast() can't remove const/invariantness.

In such case Don Clugston's example will produce compile-time error  
(because cast() can't remove invariant). And all potentially dangerous  
places in a program can be easily detected by simply greeping  
/(const|invariant)_cast/


-- 
Regards,
Yauheni Akhotnikau
June 21, 2007
Re: D2.0: an example of use-case for casting invariant away
Don Clugston wrote:
> 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.

a syntactical search would be needed instead of a grep. until 
refactoring tools for D surface, an optional compiler warning for casts 
resulting in undefined behaviour would be nice...
June 21, 2007
Casts
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
June 21, 2007
Re: D2.0: an example of use-case for casting invariant away
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.

So.. we're going to have to put up with this potential nasty bug?

What about a new cast which only removes 'const' and/or 'invariant and prohibit normal cast from removing it.

Perhaps calling it 'vary', eg.

void f(const int *b, uint c)
{
  int *d = vary() b;
}

Not sure about the (), if they're needed, or if vary(b) would be a better syntax.

The basic point being that cast cannot then cause the nasty bug and vary can be searched/grepped for.

Regan
June 21, 2007
Re: D2.0: an example of use-case for casting invariant away
Regan Heath wrote:
> 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.
> 
> So.. we're going to have to put up with this potential nasty bug?
> 
> What about a new cast which only removes 'const' and/or 'invariant and prohibit normal cast from removing it.
> 
> Perhaps calling it 'vary', eg.
> 
> void f(const int *b, uint c)
> {
>    int *d = vary() b;
> }

To avoid a new keyword...

int* d = cast(break const) b;

IMHO, we want something that looks really nasty.
June 21, 2007
Re: D2.0: an example of use-case for casting invariant away
Don Clugston skrev:

> To avoid a new keyword...
> 
> int* d = cast(break const) b;
> 
> IMHO, we want something that looks really nasty.

Reusing break is brilliant! Another alternative:

int *d = break(const) b;

/Oskar
June 21, 2007
Re: D2.0: an example of use-case for casting invariant away
Don Clugston Wrote:

> Regan Heath wrote:
> > 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.
> > 
> > So.. we're going to have to put up with this potential nasty bug?
> > 
> > What about a new cast which only removes 'const' and/or 'invariant and prohibit normal cast from removing it.
> > 
> > Perhaps calling it 'vary', eg.
> > 
> > void f(const int *b, uint c)
> > {
> >    int *d = vary() b;
> > }
> 
> To avoid a new keyword...
> 
> int* d = cast(break const) b;

what about?
int* d =cast(!const)b;
> 
> IMHO, we want something that looks really nasty.
June 21, 2007
Re: D2.0: an example of use-case for casting invariant away
Don Clugston wrote:
> To avoid a new keyword...
> 
> int* d = cast(break const) b;
> 
> IMHO, we want something that looks really nasty.

That's inspired, Don.  No need for new keywords, *and* it perfectly
conveys what it's doing.  I also like that it's somewhat longer than a
regular cast, since this is not the sort of thing you want to do lightly.

	-- Daniel
1 2 3 4
Top | Discussion index | About this forum | D home