digitalmars.D - Final, Const, Invariant
- David B. Held (60/60) Mar 23 2007 Since the Extended Type Design thread has blown my stack (and taken all
- Lutger (15/20) Mar 23 2007 Haha thanks, only know I understand it clearly, time to read some of
- Andrei Alexandrescu (See Website For Email) (3/28) Mar 23 2007 Yah.
- Dan (10/40) Mar 23 2007 I think the concept is right.
- Don Clugston (23/57) Mar 26 2007 My code has const everywhere. In fact, I use 'const' about ten times as
- Walter Bright (2/8) Mar 26 2007 Replacing const with final should do the trick.
- Don Clugston (12/22) Mar 26 2007 Will that prevent taking the address, the same way 'const' does now?
- Walter Bright (9/35) Mar 26 2007 It's ironic, the "can't take the address of a const" is actually a bug.
- Don Clugston (23/47) Mar 26 2007 So I've misunderstood the intention of 'const' all this time!
Since the Extended Type Design thread has blown my stack (and taken all the heap in my mail reader), here is my explanation of these concepts for anyone who might still be confused. Yes, the explanation is cartoony, but I hope it helps: Final This is the "Velcro(TM)" property. Any variable declared with this property is like super-glue. You stick a value to it, and it doesn't let go. You can't pull the value off it no matter how hard you try. final int x = 42; // uh-oh...what if x doesn't like 42? x = 5; // oops! x is still stuck to the 42!! final int y = x; // y is 42 final Bob alice = new Bob(); // Yay! Bob and alice got married! alice.changeBob(); // ok, final doesn't stop this... Bob.mutate(alice); // ...or this alice = pete; // Nope! alice is "monogamous"...no new Bobs for her! Final is a "storage class" because it doesn't say anything about the value we are pointing to...just us. Invariant This is the IronMan property. This is a type property, so it's a property of objects, not handles/pointers/references. No matter who points at you, your skin is an impenetrable alloy, and you remain steadfastly unchanged: invariant string s = "Hello, world"; // Yup, this friendly message is also invariant s = "Goodbye, world"; // Ok, Invariant doesn't say anything about this name, only what this name refers to s = mutableString(); // Nope! The type of s requires that we only refer to IronMan objects...s is a big fan of IronMan s.breakWill(); // Ain't gonna happen...this is IronMan, and he can't be broken! final invariant string s = "Bonjour, amigo!"; // s has an identity crisis, but it's permanent :( s = "Hola, amie!"; // Nope...final means we are married to "Bonjour..." s.reverse(); // Nuh-uh...our Franish is carved in stone Const This is the Rose Colored Glasses property. Also known as the Look-But-Don't-Touch property. Const variables are Puritanical...everything they see is invariant, or so they think. const Point* p = new Point(x, y); // Ok, even though this new Point is intrinsically mutable, our Rose Colored Glasses make us think it's really Invariant p = differentPoint; // Ok, because const is a type qualifier, which means that it affects what kinds of folks we associate with, but doesn't stop us from associating altogether p->getX(); // Ok, because getX() is also const...the underlying Point remains unchanged p->move(5, 6); // Wrong! Even though the underlying point is not invariant, we pretend that it is, because the glasses make us think the invariance is half-full final const Point* q = p; // Now we've gone and aliased p, and we can't undo it q->move(w, z); // Just as illegal as it was for p q = new Point(1, 2); // Start over? Fuhggettaboutit invariant const Point* r = new Point(8, 10); // Redundant, but legal...the underlying object is immutable, so in this case, the world Really Is Rose-Colored; we can take the glasses off, but we like the style final invariant const Point* end = new Point(double.infinity, double.infinity); // Also redundant, but this is the immutable unchangeable end of the universe. Dave
Mar 23 2007
David B. Held wrote:Since the Extended Type Design thread has blown my stack (and taken all the heap in my mail reader), here is my explanation of these concepts for anyone who might still be confused. Yes, the explanation is cartoony, but I hope it helps:Haha thanks, only know I understand it clearly, time to read some of that thread again... It is much clearer though than C++, for there it depends on where you put the const which kind of meaning it has. To sum it up, there are three kinds of 'immutability', where one (const) is a subset of another (invariant). With this, we can control the semantics we want precisely and combine them to get a grand total of five different meanings: final Object x = y; // x won't ever reference anything but y const Object* x = &y; // y can't be changed by x invariant Object x = new Object; // x can't be changed at all final const Object* x = &y; // x points to y forever and can't change y final invariant Object* x = &y; // same as above but y will never change This is right?
Mar 23 2007
Lutger wrote:David B. Held wrote:Yah. AndreiSince the Extended Type Design thread has blown my stack (and taken all the heap in my mail reader), here is my explanation of these concepts for anyone who might still be confused. Yes, the explanation is cartoony, but I hope it helps:Haha thanks, only know I understand it clearly, time to read some of that thread again... It is much clearer though than C++, for there it depends on where you put the const which kind of meaning it has. To sum it up, there are three kinds of 'immutability', where one (const) is a subset of another (invariant). With this, we can control the semantics we want precisely and combine them to get a grand total of five different meanings: final Object x = y; // x won't ever reference anything but y const Object* x = &y; // y can't be changed by x invariant Object x = new Object; // x can't be changed at all final const Object* x = &y; // x points to y forever and can't change y final invariant Object* x = &y; // same as above but y will never change This is right?
Mar 23 2007
Andrei Alexandrescu (See Website For Email) Wrote:Lutger wrote:I think the concept is right. Details, thoughts on which word ought to mean which? I agree we should use three keywords to accomplish the storage class thing. Note though that const and invariant are already keywords, and this might break some things... I'm still curious though Andrei, what about Object*[32][char[]], where we want to ensure the char[]'s are invariant? Is that Object*[32][invariant char[]] ? Also, if this gets implemented, enough needs to be explained so we can use it correctly for all the odd uses. it will have to go in the guide, mm? Can I use static with that? Do I need to? If something's invariant, is it implicitly static? So can I use myFunc( invariant char[], int x) ? What does that mean, that it won't change at all during the function operation, that it only accepts invariant char[]'s, or what? Can I use it in a tuple, template, mixin, and alias function/delegate? That needs to be decided now I think.David B. Held wrote:Yah. AndreiSince the Extended Type Design thread has blown my stack (and taken all the heap in my mail reader), here is my explanation of these concepts for anyone who might still be confused. Yes, the explanation is cartoony, but I hope it helps:Haha thanks, only know I understand it clearly, time to read some of that thread again... It is much clearer though than C++, for there it depends on where you put the const which kind of meaning it has. To sum it up, there are three kinds of 'immutability', where one (const) is a subset of another (invariant). With this, we can control the semantics we want precisely and combine them to get a grand total of five different meanings: final Object x = y; // x won't ever reference anything but y const Object* x = &y; // y can't be changed by x invariant Object x = new Object; // x can't be changed at all final const Object* x = &y; // x points to y forever and can't change y final invariant Object* x = &y; // same as above but y will never change This is right?
Mar 23 2007
Dan wrote:Andrei Alexandrescu (See Website For Email) Wrote:My code has const everywhere. In fact, I use 'const' about ten times as often as 'static' or 'class'. And the new scheme does not seem to have a direct equivalent for it. How can I say, "I want to refer this literal by a name, but in all other respects I want it to behave exactly as a literal"? In particular, I do not want storage associated with it (attempting to take its address is a bug), and it should work with CTFE. There's an ugly hack where you can use an anonymous enum, but it only works for integral types; does not work for floating point or string literals. Note that named floating point constants are extremely common in scientific code. In fact, it's almost always bad style to use an unnamed floating point literal! If 'const' is used as described in the new scheme, seriously consider if we need a 'literal' or 'define' keyword. Since I suspect that I'm losing the battle for 'const'=='literal', I have a suggestion. The best word I've come up with for what the proposed 'const' means is 'constrained'. Which is interesting because of the way you'd abbreviate it... eg. const Object* x = &y; // y can't be changed by x --> x is constrained in what it can do to y. 'const' could be described as an abbreviation of 'constrained' rather than 'constant'.Lutger wrote:I think the concept is right. Details, thoughts on which word ought to mean which? I agree we should use three keywords to accomplish the storage class thing. Note though that const and invariant are already keywords, and this might break some things...David B. Held wrote:Yah. AndreiSince the Extended Type Design thread has blown my stack (and taken all the heap in my mail reader), here is my explanation of these concepts for anyone who might still be confused. Yes, the explanation is cartoony, but I hope it helps:Haha thanks, only know I understand it clearly, time to read some of that thread again... It is much clearer though than C++, for there it depends on where you put the const which kind of meaning it has. To sum it up, there are three kinds of 'immutability', where one (const) is a subset of another (invariant). With this, we can control the semantics we want precisely and combine them to get a grand total of five different meanings: final Object x = y; // x won't ever reference anything but y const Object* x = &y; // y can't be changed by x invariant Object x = new Object; // x can't be changed at all final const Object* x = &y; // x points to y forever and can't change y final invariant Object* x = &y; // same as above but y will never change This is right?
Mar 26 2007
Don Clugston wrote:My code has const everywhere. In fact, I use 'const' about ten times as often as 'static' or 'class'. And the new scheme does not seem to have a direct equivalent for it. How can I say, "I want to refer this literal by a name, but in all other respects I want it to behave exactly as a literal"? In particular, I do not want storage associated with it (attempting to take its address is a bug), and it should work with CTFE.Replacing const with final should do the trick.
Mar 26 2007
Walter Bright wrote:Don Clugston wrote:Will that prevent taking the address, the same way 'const' does now? There's also this previously discussed case: void func(int x) { final a = ctfe_func(7); // will never change, ever. final b = non_ctfe_func(8); // won't change during this function call } A largely unrelated question, why are existing 'const' items stored in the obj file (instead of being discarded immediately after use)? (I'm excluding uninitialised class 'const' items set in the constructor, which are fundamentally different).My code has const everywhere. In fact, I use 'const' about ten times as often as 'static' or 'class'. And the new scheme does not seem to have a direct equivalent for it. How can I say, "I want to refer this literal by a name, but in all other respects I want it to behave exactly as a literal"? In particular, I do not want storage associated with it (attempting to take its address is a bug), and it should work with CTFE.Replacing const with final should do the trick.
Mar 26 2007
Don Clugston wrote:Walter Bright wrote:It's ironic, the "can't take the address of a const" is actually a bug. I guess it has inadvertently turned into a feature! I could argue it either way.Don Clugston wrote:Will that prevent taking the address, the same way 'const' does now?My code has const everywhere. In fact, I use 'const' about ten times as often as 'static' or 'class'. And the new scheme does not seem to have a direct equivalent for it. How can I say, "I want to refer this literal by a name, but in all other respects I want it to behave exactly as a literal"? In particular, I do not want storage associated with it (attempting to take its address is a bug), and it should work with CTFE.Replacing const with final should do the trick.There's also this previously discussed case: void func(int x) { final a = ctfe_func(7); // will never change, ever.Make it static final. There's no reason to put such a declaration on the stack.final b = non_ctfe_func(8); // won't change during this function callLeave as is.} A largely unrelated question, why are existing 'const' items stored in the obj file (instead of being discarded immediately after use)?Because it's a bug that one cannot take the address of them. But it could become a feature, in which case they shouldn't be put in the obj file.(I'm excluding uninitialised class 'const' items set in the constructor, which are fundamentally different).
Mar 26 2007
Walter Bright wrote:Don Clugston wrote:So I've misunderstood the intention of 'const' all this time! Actually, I don't know how it could work, with the way D does constant folding. Currently, a literal like 3.1f is *not* the nearest value to 3.1 which will fit into a float, but rather it's the value 3.1, represented as accurately as possible, with a type of 'float'. const float F1 = float.max * 100.0; const float F2 = F1/200.0; // sets F2 = float.max/2. But if the literal is stored in the executable, it has to be changed into 'the nearest value which will fit into a float'. So precision drops, and overflow values become infinity. double D1 = F1; // D1 = float.max*100.0 double D2 = F1/200.0; // D2 = float.max/2. double X1 = *(&F1); // X1 = infinity double X2 = *(&F1)/200.0; // X2 = infinity Which would mean that the same symbol can have a run time value which is different to its compile time value. IMHO, the fact that D currently doesn't allow you to access the run time value is a great feature, that is consistent with the constant folding, and protects you from subtle bugs.Walter Bright wrote:It's ironic, the "can't take the address of a const" is actually a bug. I guess it has inadvertently turned into a feature! I could argue it either way.Don Clugston wrote:Will that prevent taking the address, the same way 'const' does now?My code has const everywhere. In fact, I use 'const' about ten times as often as 'static' or 'class'. And the new scheme does not seem to have a direct equivalent for it. How can I say, "I want to refer this literal by a name, but in all other respects I want it to behave exactly as a literal"? In particular, I do not want storage associated with it (attempting to take its address is a bug), and it should work with CTFE.Replacing const with final should do the trick.I think it would improve executable size, and possibly compilation time as well.A largely unrelated question, why are existing 'const' items stored in the obj file (instead of being discarded immediately after use)?Because it's a bug that one cannot take the address of them. But it could become a feature, in which case they shouldn't be put in the obj file.
Mar 26 2007