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.

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

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

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.

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

"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

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

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