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:
> To avoid a new keyword...
> 
> int* d = cast(break const) b;
> 
> IMHO, we want something that looks really nasty.

Great!  ++votes;



-- 
Tomasz Stachowiak
http://h3.team0xf.com/
h3/h3r3tic on #D freenode
June 21, 2007
Re: D2.0: an example of use-case for casting invariant away
Don Clugston wrote:
> Walter Bright wrote:
>> 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 think you're right.

> 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.

This is why some languages disallow unions completely. But I'm not 
concerned about this case, as it's a deliberate attempt to circumvent 
the typing rules. If someone is doing it deliberately, D gives them the 
benefit of the doubt and presumes they know what they're doing. I'm only 
concerned about the former inadvertent case.
June 22, 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;
> 
> IMHO, we want something that looks really nasty.

New keyword? Why a new syntax a at all? This is the kind of stuff that 
should be possible to do with D's (current or future) meta programming 
capabilities. Here's a small proof of concept of what can currently be 
done in D:

void main(char[][] args) {
  const(char *) cfoo;
  char* foo = unConst(cfoo);
  writeln(typeid(typeof(unConst(cfoo))));

  const(char **) cfoo2;
  char** foo2 = unConst(cfoo2);
  writeln(typeid(typeof(unConst(cfoo2))));
}

unConstType!(T) unConst(T)(T val) {
	writeln(typeid(unConstType!(T)));
	return cast(unConstType!(T)) val;
}

template unConstType(T : T*) {
	pragma(msg, "*");
	alias unConstType!(T)* unConstType;
}
template unConstType(T) {
	alias typeof(T) unConstType;
}


It only unconstifies pointers (but that's easily extendable to other 
native types), and the value returned cannot be used as an lvalue, but 
in any case this is just to demonstrate that no new syntax should be 
required.
The other case, a cast that only changes the core type, and not the 
modifiers, i.e., something like:

  const(char*) a = ...;
  auto b = castBaseType!(int *)(a);
  //typeof(b) == const(int *)

should also be possible to implement at the meta-programming level.


-- 
Bruno Medeiros - MSc in CS/E student
http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
June 22, 2007
Re: D2.0: an example of use-case for casting invariant away
Bruno Medeiros wrote:
> and the value returned cannot be used as an lvalue, but 
> in any case this is just to demonstrate that no new syntax should be 
> required.
> 

Hum, there is a verbose, but effective, way to go around the lvalue 
problem, just simply use unConstType directly:

  char* foo = cast(unConstType!(typeof(cfoo))) cfoo;

-- 
Bruno Medeiros - MSc in CS/E student
http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
June 23, 2007
Re: D2.0: an example of use-case for casting invariant away
Bruno Medeiros wrote:
> 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;
>>
>> IMHO, we want something that looks really nasty.
> 
> New keyword? Why a new syntax a at all? This is the kind of stuff that 
> should be possible to do with D's (current or future) meta programming 
> capabilities. Here's a small proof of concept of what can currently be 
> done in D:
[snip]

Because as long as _any_ cast can remove const, you haven't fixed the problem.
The challenge is to make it extremely difficult to remove const, but still 
possible. And easy to grep for instances of it.
June 23, 2007
Re: D2.0: an example of use-case for casting invariant away
Don Clugston wrote:
> Bruno Medeiros wrote:
>> 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;
>>>
>>> IMHO, we want something that looks really nasty.
>>
>> New keyword? Why a new syntax a at all? This is the kind of stuff that 
>> should be possible to do with D's (current or future) meta programming 
>> capabilities. Here's a small proof of concept of what can currently be 
>> done in D:
> [snip]
> 
> Because as long as _any_ cast can remove const, you haven't fixed the 
> problem.
> The challenge is to make it extremely difficult to remove const, but 
> still possible. And easy to grep for instances of it.

I don't understand. Maybe I'm misunderstanding the problem, but Regan said:
"What about a new cast which only removes 'const' and/or 'invariant
and prohibit normal cast from removing it."
What I proposed was a template that would remove const, and another 
template that would change the core type, but maintain the modifiers 
(such as const/invariant) of the original type. This means *one would 
not use cast (directly) anymore*. This would be easily greppable (if the 
template's names were standard), and would remove the problem of 
accidently removing const/invariant, because you would only remove 
const/invariant (using the appropriate template) when you really want to 
do just that.



-- 
Bruno Medeiros - MSc in CS/E student
http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
June 24, 2007
Re: D2.0: an example of use-case for casting invariant away
On 6/21/07, Don Clugston <dac@nospam.com.au> wrote:
> To avoid a new keyword...
>
> int* d = cast(break const) b;
>
> IMHO, we want something that looks really nasty.
>

Only jumping in to say that looks excellent! votes++;

-- 
Anders
June 24, 2007
Re: D2.0: an example of use-case for casting invariant away
"Damnit; I don't understand what's going wrong here."

"It looks like you're modifying const data.  Did you cast const away
anywhere?"

"I use unConst, and I already checked all the lines that use that, and
they're fine!"

"But what if you *forgot* to use unConst?"

"... Uh-oh."

The problem with your suggestions is that unless either A) it's
compiler-enforced or B) humans suddenly become infallible, it's really
not solving the problem at all.  If someone forgets to use unConst, or
worse, casts away const *without realising it*, they're screwed.

And I *really* doubt B is going to happen.

	-- Daniel
June 24, 2007
Re: D2.0: an example of use-case for casting invariant away
Don Clugston wrote:
> int* d = cast(break const) b;
> 
> IMHO, we want something that looks really nasty.

Based on all the discussion in this thread, I like this alternative 
best.  I'd only insist that if someone did int *d = cast(int*) b; that 
the compiler would issue an error saying to use cast(break const) instead
June 24, 2007
Re: D2.0: an example of use-case for casting invariant away
Jason House wrote:
> Don Clugston wrote:
>> int* d = cast(break const) b;
>>
>> IMHO, we want something that looks really nasty.
> 
> Based on all the discussion in this thread, I like this alternative
> best.  I'd only insist that if someone did int *d = cast(int*) b; that
> the compiler would issue an error saying to use cast(break const) instead

Interesting: my experience suggests that it shouldn't do so.
Those who know enough to use cast(break const) appropriately
will find out how to do so.  Others would just read the error
message and blindly do what it said, pausing only briefly to
wonder why the compiler issued an error message if it knew
exactly how to "fix" the code.  Far too many programmers'
first reaction to type warnings/errors is to add casts and
mask the problem rather than addressing root cause.

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