digitalmars.D - D2.0: an example of use-case for casting invariant away
- eao197 (19/19) Jun 18 2007 Hello!
- Brad Roberts (10/32) Jun 18 2007 First, is the library actually treating the initString as read only? If...
- Walter Bright (6/9) Jun 18 2007 The need to be able to cast away const-ness is to interface to libraries...
- Sean Kelly (5/16) Jun 18 2007 That's understandable, but isn't it contrary to your statement that
- Daniel Keep (9/28) Jun 18 2007 Walter's said on a few occasions that the problem with C++'s const is
- Walter Bright (5/13) Jun 18 2007 More specifically, in C++, you can cast away const-ness and then modify
- James Dennett (10/24) Jun 18 2007 More specifically still, in C++ you can cast away const-ness and then
- Walter Bright (4/6) Jun 19 2007 C++ has too much implementation defined and undefined behavior. D has
- Don Clugston (17/32) Jun 21 2007 It sounds that in D, it will be too easy to cast away constness accident...
- Walter Bright (3/29) Jun 21 2007 No, you're not missing something. It is a general problem with cast -
- Don Clugston (13/43) Jun 21 2007 This means that cast() has just become even more unsafe. So for 2.0, it ...
- Oskar Linde (35/71) Jun 21 2007 I had look at the places I use casts in some of my projects, and found
- Walter Bright (7/23) Jun 21 2007 This is why some languages disallow unions completely. But I'm not
- eao197 (16/33) Jun 21 2007 =
- Regan Heath (11/41) Jun 21 2007 So.. we're going to have to put up with this potential nasty bug?
- Don Clugston (4/44) Jun 21 2007 To avoid a new keyword...
- Oskar Linde (4/9) Jun 21 2007 Reusing break is brilliant! Another alternative:
- Eugene Pelekhay (3/50) Jun 21 2007 what about?
- Daniel Keep (5/10) Jun 21 2007 That's inspired, Don. No need for new keywords, *and* it perfectly
- Tom S (6/11) Jun 21 2007 Great! ++votes;
- Bruno Medeiros (37/85) Jun 22 2007 New keyword? Why a new syntax a at all? This is the kind of stuff that
- Bruno Medeiros (7/11) Jun 22 2007 Hum, there is a verbose, but effective, way to go around the lvalue
- Don Clugston (5/59) Jun 23 2007 [snip]
- Bruno Medeiros (15/76) Jun 23 2007 I don't understand. Maybe I'm misunderstanding the problem, but Regan sa...
- Daniel Keep (13/13) Jun 23 2007 "Damnit; I don't understand what's going wrong here."
- Bruno Medeiros (8/28) Jun 25 2007 If you're not meant to write any cast, how the hell does one
- BCS (6/8) Jun 25 2007 somthing like this maybe?
- Anders Bergh (4/7) Jun 23 2007 Only jumping in to say that looks excellent! votes++;
- Jason House (4/7) Jun 24 2007 Based on all the discussion in this thread, I like this alternative
- James Dennett (10/18) Jun 24 2007 Interesting: my experience suggests that it shouldn't do so.
- Jason House (17/36) Jun 24 2007 ... And what about those programmers who know what they're doing but
- James Dennett (12/42) Jun 24 2007 They'll know what to do. This isn't obscure; knowing how to
- Don Clugston (8/33) Jun 24 2007 In general, I agree with you, but remember that in this case, cast(break...
- Carlos Santander (8/27) Jun 24 2007 But they're going to find it anyway. They'll read an error message, come...
- torhu (5/33) Jun 24 2007 What if the error message is something like 'can't assign const int* b
- Jascha Wetzel (4/20) Jun 21 2007 a syntactical search would be needed instead of a grep. until
- Daniel Keep (14/14) Jun 18 2007 In addition to Brad's response, note that this is *not* "casting
Hello! It is a question only for clarification for myself. If I understand = http://www.digitalmars.com/d/final-const-invariant.html correctly the = casting invariant away allowed for situations like this: // An interface for some third-party library // (which is probably written in some exotic language). extern(C) void initSomeSubsystem( char * initializationString ); ... // Our D2.0 stuff. int main() { invariant char* initializationString =3D "..."; // Casting invariant away is necessary here. initSomeSubsystem( cast(invariant) initializationString ); } Am I correct? -- = Regards, Yauheni Akhotnikau
Jun 18 2007
eao197 wrote:Hello! It is a question only for clarification for myself. If I understand http://www.digitalmars.com/d/final-const-invariant.html correctly the casting invariant away allowed for situations like this: // An interface for some third-party library // (which is probably written in some exotic language). extern(C) void initSomeSubsystem( char * initializationString ); ... // Our D2.0 stuff. int main() { invariant char* initializationString = "..."; // Casting invariant away is necessary here. initSomeSubsystem( cast(invariant) initializationString ); } Am I correct? --Regards, Yauheni AkhotnikauFirst, is the library actually treating the initString as read only? If it's not, then you shouldn't pass an invariant (or const) string down to it. The results would be undefined. If it's actually treating the string as read-only, then I'd be tempted to change the extern(c) declaration to pass the argument as const char * rather than casting away the invariantness. Note, I haven't tried this, just an off the top of my head suggestion. Later, Brad
Jun 18 2007
Brad Roberts wrote:If it's actually treating the string as read-only, then I'd be tempted to change the extern(c) declaration to pass the argument as const char * rather than casting away the invariantness.The need to be able to cast away const-ness is to interface to libraries that you cannot go and change. Also, the type system is not meant to be a straitjacket. If you absolutely must do something, and you know what you are doing, there should be a way to do it.
Jun 18 2007
Walter Bright wrote:Brad Roberts wrote:That's understandable, but isn't it contrary to your statement that const in C++ is useless because of const_cast? Or is it the presence of a cast specifically intended to cast away const that you take issue with? SeanIf it's actually treating the string as read-only, then I'd be tempted to change the extern(c) declaration to pass the argument as const char * rather than casting away the invariantness.The need to be able to cast away const-ness is to interface to libraries that you cannot go and change. Also, the type system is not meant to be a straitjacket. If you absolutely must do something, and you know what you are doing, there should be a way to do it.
Jun 18 2007
Sean Kelly wrote:Walter Bright wrote:Walter's said on a few occasions that the problem with C++'s const is that casting away const is a *well-defined* operation. That means that const cannot be used to do any kind of optimisation, since it doesn't really mean anything. The new page on const specifically states that casting away const or invariance is *not* a well-defined operation, and you'd better know what you're doing when you do it. -- DanielBrad Roberts wrote:That's understandable, but isn't it contrary to your statement that const in C++ is useless because of const_cast? Or is it the presence of a cast specifically intended to cast away const that you take issue with? SeanIf it's actually treating the string as read-only, then I'd be tempted to change the extern(c) declaration to pass the argument as const char * rather than casting away the invariantness.The need to be able to cast away const-ness is to interface to libraries that you cannot go and change. Also, the type system is not meant to be a straitjacket. If you absolutely must do something, and you know what you are doing, there should be a way to do it.
Jun 18 2007
Daniel Keep wrote:Walter's said on a few occasions that the problem with C++'s const is that casting away const is a *well-defined* operation. That means that const cannot be used to do any kind of optimisation, since it doesn't really mean anything. The new page on const specifically states that casting away const or invariance is *not* a well-defined operation, and you'd better know what you're doing when you do it.More specifically, in C++, you can cast away const-ness and then modify the underlying data, and this is defined to be legal, defined behavior. With D, you can cast away const-ness, that is legal. But if you subsequently modify the underlying data, that is undefined behavior.
Jun 18 2007
Walter Bright wrote:Daniel Keep wrote:More specifically still, in C++ you can cast away const-ness and then modify the underlying object only if that underlying object is not defined as being const. If you modify an object that is actually const (where I think Walter might say that it has const as it "storage class", though that doesn't match C++ terminology) then you have undefined behavior.Walter's said on a few occasions that the problem with C++'s const is that casting away const is a *well-defined* operation. That means that const cannot be used to do any kind of optimisation, since it doesn't really mean anything. The new page on const specifically states that casting away const or invariance is *not* a well-defined operation, and you'd better know what you're doing when you do it.More specifically, in C++, you can cast away const-ness and then modify the underlying data, and this is defined to be legal, defined behavior.With D, you can cast away const-ness, that is legal. But if you subsequently modify the underlying data, that is undefined behavior.Seems reasonable to me (though one of C++'s faults is that it has *too much* undefined behavior). -- James
Jun 18 2007
James Dennett wrote:Seems reasonable to me (though one of C++'s faults is that it has *too much* undefined behavior).C++ has too much implementation defined and undefined behavior. D has less, but it should be even less. ID and UB impede source portability.
Jun 19 2007
Walter Bright wrote:Daniel Keep 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. 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?Walter's said on a few occasions that the problem with C++'s const is that casting away const is a *well-defined* operation. That means that const cannot be used to do any kind of optimisation, since it doesn't really mean anything. The new page on const specifically states that casting away const or invariance is *not* a well-defined operation, and you'd better know what you're doing when you do it.More specifically, in C++, you can cast away const-ness and then modify the underlying data, and this is defined to be legal, defined behavior. With D, you can cast away const-ness, that is legal. But if you subsequently modify the underlying data, that is undefined behavior.
Jun 21 2007
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.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?
Jun 21 2007
Walter Bright wrote:Don Clugston wrote: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.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.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?
Jun 21 2007
Don Clugston skrev:Walter Bright wrote: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 double randomDelta() { return (rand() % 3) - 1; } 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 got something like generic method injection, one could replace cast(double) intVar with intVar.toDouble, or intVar.to!(double) but is that any better? /OskarDon Clugston wrote: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.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.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?
Jun 21 2007
Don Clugston wrote:Walter Bright wrote:I think you're right.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.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.
Jun 21 2007
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 =3D cast(uint *)b; d +=3D c; } Months later, I'm refactoring the code, and I convert the int * ==parameter to an invariant, without recognising that it's changing the=D =value of b. Oops. C++'s const would catch this mistake, but if I understand correctly,=he =will compile it without error. Suddenly the function has moved into t==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
Jun 21 2007
Walter Bright Wrote:Don Clugston wrote: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. ReganWalter 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.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?
Jun 21 2007
Regan Heath wrote:Walter Bright Wrote:To avoid a new keyword... int* d = cast(break const) b; IMHO, we want something that looks really nasty.Don Clugston wrote: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; }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.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?
Jun 21 2007
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
Jun 21 2007
Don Clugston Wrote:Regan Heath wrote:what about? int* d =cast(!const)b;Walter Bright Wrote:To avoid a new keyword... int* d = cast(break const) b;Don Clugston wrote: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; }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.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?IMHO, we want something that looks really nasty.
Jun 21 2007
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
Jun 21 2007
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
Jun 21 2007
Don Clugston wrote:Regan Heath wrote: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#DWalter Bright Wrote:To avoid a new keyword... int* d = cast(break const) b; IMHO, we want something that looks really nasty.Don Clugston wrote: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; }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.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?
Jun 22 2007
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
Jun 22 2007
Bruno Medeiros wrote:Don Clugston wrote:[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.Regan Heath wrote: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:Walter Bright Wrote:To avoid a new keyword... int* d = cast(break const) b; IMHO, we want something that looks really nasty.Don Clugston wrote: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; }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.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?
Jun 23 2007
Don Clugston wrote:Bruno Medeiros wrote: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#DDon Clugston wrote:[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.Regan Heath wrote: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:Walter Bright Wrote:To avoid a new keyword... int* d = cast(break const) b; IMHO, we want something that looks really nasty.Don Clugston wrote: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; }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.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?
Jun 23 2007
"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
Jun 23 2007
Daniel Keep wrote:"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. -- DanielIf you're not meant to write any cast, how the hell does one accidentally write a cast? (http://www.flicklife.com/edecadcc9a8691762b4f/The_Daily_Show_S rver_Crossfire.html :P ) -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Jun 25 2007
Reply to Bruno,If you're not meant to write any cast, how the hell does one accidentally write a cast?somthing like this maybe? int[] foo; // an array of ints const int[]* pfoo; // a pointer to an array of ints auto pdfoo = cast(dchar[]*)pfoo; // a pointer to the same data but as dchars (*pdfoo)[5] = 'h'; //oops
Jun 25 2007
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
Jun 23 2007
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
Jun 24 2007
Jason House wrote:Don Clugston wrote: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. -- Jamesint* 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
Jun 24 2007
James Dennett wrote:Jason House wrote:... And what about those programmers who know what they're doing but don't know the ins and outs of the language perfectly? Should they start scouring the documentation and news groups to find the proper fix? IMHO, error messages should be as helpful as possible. Besides giving a new syntax with "break const" embedded within it. I don't think there's really anything else we can do to stop crazy programmers who'll do anything to get their code to function. D has many cool features that attracted me to use it, but I'm already near my limit of frustration using such a volatile language. PS: How do you fix a large program that gives just this one compilation error (with gdc after compiling and running perfectly with dmd): /include/d/4.1.1/std/traits.d:134: Error: void initializer has no value $ head -n 134 /include/d/4.1.1/std/traits.d | tail -n 3 template isStaticArray_impl(T) { const T inst = void;Don Clugston wrote: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. -- Jamesint* 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
Jun 24 2007
Jason House wrote:James Dennett wrote:They'll know what to do. This isn't obscure; knowing how to handle issues such as constness is basic to any language which supports such a notion. Programmers who "Know what they're doing" know what they're doing. They're just in the minority.Jason House wrote:... And what about those programmers who know what they're doing but don't know the ins and outs of the language perfectly?Don Clugston wrote: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. -- Jamesint* 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) insteadShould they start scouring the documentation and news groups to find the proper fix?Even if they didn't know, it shouldn't take much to find the answer. Typing the error message into Google would likely do the job.IMHO, error messages should be as helpful as possible. Besides giving a new syntax with "break const" embedded within it. I don't think there's really anything else we can do to stop crazy programmers who'll do anything to get their code to function.You can't stop people writing bad code, but you can avoid making the bad code easier to write than the good code in many cases. -- James
Jun 24 2007
Jason House wrote:James Dennett wrote:In general, I agree with you, but remember that in this case, cast(break const) is an ugly hack which leads you into undefined behaviour. It's not like C++'s const_cast<> which is well-defined. I don't think we want Microsoft's paperclip: "You like you're trying to hang yourself, would you some help?". <g> Hopefully breaking const is very, very rare. If a novice program actually needs to break const in ordinary situations, there's a big language problem.Jason House wrote:... And what about those programmers who know what they're doing but don't know the ins and outs of the language perfectly? Should they start scouring the documentation and news groups to find the proper fix?Don Clugston wrote: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. -- Jamesint* 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
Jun 24 2007
James Dennett escribió:Jason House wrote:But they're going to find it anyway. They'll read an error message, come here and ask what that means, someone will tell them to use cast(break const), and they'll be left wondering why the compiler couldn't tell that in the first place. Not only that, but after a while it'll become FAQ material. I agree with your point, but not much will be gained in the end. -- Carlos Santander BernalDon Clugston wrote: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. -- Jamesint* 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
Jun 24 2007
Carlos Santander wrote:James Dennett escribió:What if the error message is something like 'can't assign const int* b to non-const int* d'? If they really want a const cast, they'll then go look at the docs for cast expressions to see why it didn't work. Otherwise, they'll try making d a const.Jason House wrote:But they're going to find it anyway. They'll read an error message, come here and ask what that means, someone will tell them to use cast(break const), and they'll be left wondering why the compiler couldn't tell that in the first place. Not only that, but after a while it'll become FAQ material. I agree with your point, but not much will be gained in the end.Don Clugston wrote: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. -- Jamesint* 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
Jun 24 2007
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...
Jun 21 2007
In addition to Brad's response, note that this is *not* "casting invariant away". You are *adding* invariant[1]. This might be more accurate: extern(C) void initSomeSubsystem(char * initializationString); int main() { invariant char * initString = "..."; // Cast away invariantness of initString so we can pass it to the C // function; be it on your head if the function tries to change it! initSomeSubsystem( cast(char*)initString ); } -- Daniel [1] Although it's already there, so it wouldn't have any effect, I don't think.
Jun 18 2007