June 21, 2007 Re: D2.0: an example of use-case for casting invariant away | ||||
---|---|---|---|---|
| ||||
Posted in reply to Don Clugston | 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 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Don Clugston | 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 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Don Clugston | 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 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Bruno Medeiros | 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 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Bruno Medeiros | 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 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Don Clugston | 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 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Don Clugston | 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 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Bruno Medeiros | "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 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Don Clugston | 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 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jason House | 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
|
Copyright © 1999-2021 by the D Language Foundation