www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - It's worse than I thought

reply "Janice Caron" <caron800 googlemail.com> writes:
It's worse than I thought. This compiles and runs, both in D2.007 and in D2.008

void main()
{
	const(int) ci = 1;
	invariant(int) ii = 2;
	
	++ci;
	++ii;
}

It is now becoming quite clear that the "const mess" is very much
still with us, and this sort of thing really doesn't help D at all.
Nov 30 2007
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Janice Caron wrote:
 It's worse than I thought. This compiles and runs, both in D2.007 and in D2.008
 
 void main()
 {
 	const(int) ci = 1;
 	invariant(int) ii = 2;
 	
 	++ci;
 	++ii;
 }
 
 It is now becoming quite clear that the "const mess" is very much
 still with us, and this sort of thing really doesn't help D at all.
It turns out that making a variable that is typed const (rather than storage class const) immutable makes it impossible to use const references: class C { } const(C) c; if (...) c = ...; else c = ...; So, variables that are typed const are rebindable. Note that this doesn't break const, as you can always make a copy of a const. To get a non-rebindable const: const C c;
Nov 30 2007
next sibling parent reply "Janice Caron" <caron800 googlemail.com> writes:
On Nov 30, 2007 10:52 AM, Walter Bright <newshound1 digitalmars.com> wrote:
 It turns out that making a variable that is typed const (rather than
 storage class const) immutable makes it impossible to use const references:
 So, variables that are typed const are rebindable.
Yes, there is another thread on that somewhere. It's got some long arguments in it, which it would be silly to repeat here, but in the end I proposed the syntaxes: const(C) c; const(C) ref c; The first makes both the reference and the data const; the second makes only the data const, but the reference rebindable. (Other people have suggested alternative syntaxes through the ages, so don't think I'm particularly hung up on mine, it's just that it seems very clear what's being said).
 Note that this
 doesn't break const
Nobody's saying anything is broken. What I'm saying is that it's TOO CONFUSING. This can break D. I mean, on other threads, you told us that "const X x" was the same thing as "const(X) x". Now it turns out that's not true. The only, and I mean *ONLY*, thing that makes intuitive sense, is that when I write const(...), it must mean that everything inside the brackets, and nothing else, is const. Nothing else makes sense.
Nov 30 2007
parent reply gide nwawudu.com writes:
On Fri, 30 Nov 2007 11:06:53 +0000, "Janice Caron"
<caron800 googlemail.com> wrote:

On Nov 30, 2007 10:52 AM, Walter Bright <newshound1 digitalmars.com> wrote:
 It turns out that making a variable that is typed const (rather than
 storage class const) immutable makes it impossible to use const references:
 So, variables that are typed const are rebindable.
Yes, there is another thread on that somewhere. It's got some long arguments in it, which it would be silly to repeat here, but in the end I proposed the syntaxes: const(C) c; const(C) ref c; The first makes both the reference and the data const; the second makes only the data const, but the reference rebindable. (Other people have suggested alternative syntaxes through the ages, so don't think I'm particularly hung up on mine, it's just that it seems very clear what's being said).
 Note that this
 doesn't break const
Nobody's saying anything is broken. What I'm saying is that it's TOO CONFUSING. This can break D. I mean, on other threads, you told us that "const X x" was the same thing as "const(X) x". Now it turns out that's not true. The only, and I mean *ONLY*, thing that makes intuitive sense, is that when I write const(...), it must mean that everything inside the brackets, and nothing else, is const. Nothing else makes sense.
</lurk> I agree with Janice on this, I was under the (wrong) impression that 'const(C)' and 'const C' were synonymous. Maybe the following syntax will work? const (C) c = new C; c = new C; // Error; c.set(...); // Error const (ref C) c = new C; c = new C; // Error; c.set(...); // Ok const (C.) c = new C; c = new C; // Ok; c.set(...); // Error Gide
Nov 30 2007
parent reply "Janice Caron" <caron800 googlemail.com> writes:
On Nov 30, 2007 3:48 PM,  <gide nwawudu.com> wrote:
 I was under the (wrong) impression that
 'const(C)' and 'const C'  were synonymous.
Some time ago, Walter started a thread called something like "const sucks", in which he agreed that D2.007 const was a mess, and promised to go away and rethink it. He has indeed done that - however, the only change I can observe is that "head const" has been ditched, along with the keyword "final". Everything else that was bad about const is still there. I find this distressing, because I /love/ what Walter is trying to do. D-const could be way, way, w-a-y, better than C++ const. I love that const is transitive. I'm prepared to live without "logical const" and see what happens. I love the fact that the language distinguishes between const and invariant, where it makes sense to do that. I love that "const(int***)***" is so much more concise than C++'s corresponding "int const*const*const*const***". All of this is GREAT! But what I hate about it is the confusion between (1) const as a type-constructor, (2) const as a storage class for variables, (3) const as a function parameter storage class, and (4) const as a storage class for member functions. (And ditto for invariant). I further hate that const/invariant don't apply to declared symbols (sometimes). Huh!? So here are my suggestions for clearing up the mess. They are very simple, clean, and elegant: (1) ditch "const as a storage class" altogther. Keep "const as a type-constructor". Stick rigidly to the principle that "const(...)" means "the stuff in the brackets is const", and nothing else. (2) allow "const T", where T is a type, to be syntactic sugar for "const(T)". But it's still just a type constructor. (3) use the syntax "const(this)" for const member functions. Make "const(this)" an attribute. Ideally, extend the principle to "const(anyIdentifier)", but just "const(this)" will do for now. (4) let "const(C)&" be the syntax for making mutable references to const classes. (5) let "const x = y;" be syntactic sugar for "const(typeof(y)) x = y;" And the same for invariant. ...and that's it!
Nov 30 2007
parent reply "Craig Black" <cblack ara.com> writes:
"Janice Caron" <caron800 googlemail.com> wrote in message 
news:mailman.199.1196440211.2338.digitalmars-d puremagic.com...
 On Nov 30, 2007 3:48 PM,  <gide nwawudu.com> wrote:
 I was under the (wrong) impression that
 'const(C)' and 'const C'  were synonymous.
Some time ago, Walter started a thread called something like "const sucks", in which he agreed that D2.007 const was a mess, and promised to go away and rethink it. He has indeed done that - however, the only change I can observe is that "head const" has been ditched, along with the keyword "final". Everything else that was bad about const is still there. I find this distressing, because I /love/ what Walter is trying to do. D-const could be way, way, w-a-y, better than C++ const. I love that const is transitive. I'm prepared to live without "logical const" and see what happens. I love the fact that the language distinguishes between const and invariant, where it makes sense to do that. I love that "const(int***)***" is so much more concise than C++'s corresponding "int const*const*const*const***". All of this is GREAT! But what I hate about it is the confusion between (1) const as a type-constructor, (2) const as a storage class for variables, (3) const as a function parameter storage class, and (4) const as a storage class for member functions. (And ditto for invariant). I further hate that const/invariant don't apply to declared symbols (sometimes). Huh!? So here are my suggestions for clearing up the mess. They are very simple, clean, and elegant: (1) ditch "const as a storage class" altogther. Keep "const as a type-constructor". Stick rigidly to the principle that "const(...)" means "the stuff in the brackets is const", and nothing else. (2) allow "const T", where T is a type, to be syntactic sugar for "const(T)". But it's still just a type constructor. (3) use the syntax "const(this)" for const member functions. Make "const(this)" an attribute. Ideally, extend the principle to "const(anyIdentifier)", but just "const(this)" will do for now.
I like the const(this) idea. Very explicit.
 (4) let "const(C)&" be the syntax for making mutable references to
 const classes.
I don't think adding an amphersand makes it any more understandable.
 (5) let "const x = y;" be syntactic sugar for "const(typeof(y)) x = y;"
Sure. We can't already do this?
 And the same for invariant.


 ...and that's it! 
Nov 30 2007
next sibling parent "Craig Black" <cblack ara.com> writes:
 (4) let "const(C)&" be the syntax for making mutable references to
 const classes.
I don't think adding an amphersand makes it any more understandable.
Maybe const(ref) could be used just like const(this). const X x; // The reference is mutable const(ref) X x; // The data is mutable const(ref) const X x; // Nothing is mutable
Nov 30 2007
prev sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 11/30/07, Craig Black <cblack ara.com> wrote:
 (4) let "const(C)&" be the syntax for making mutable references to
 const classes.
I don't think adding an amphersand makes it any more understandable.
If you think of the ampersand as meaning "reference to", in the same way that asterisk means "pointer to", then it makes a lot of sense. I did a long explanation of this on the other thread. Essentially, what we're saying is that because the ampersand is outside the brackets, then "reference to" isn't const. We do need a way of expressing "mutable reference to const class", though. If this isn't the right syntax, I'm sure we can come up with another one.
 (5) let "const x = y;" be syntactic sugar for "const(typeof(y)) x = y;"
Sure. We can't already do this?
My rule (5) was necessary because of my rule (1). Janice's rule (1) would make "const x = y;" (which is currently legal, as you say) illegal, so I introduced rule (5) to put it back.
Nov 30 2007
prev sibling parent reply =?ISO-8859-1?Q?S=F6nke_Ludwig?= writes:
Walter Bright wrote:
 Janice Caron wrote:
 It's worse than I thought. This compiles and runs, both in D2.007 and 
 in D2.008

 void main()
 {
     const(int) ci = 1;
     invariant(int) ii = 2;
     
     ++ci;
     ++ii;
 }

 It is now becoming quite clear that the "const mess" is very much
 still with us, and this sort of thing really doesn't help D at all.
It turns out that making a variable that is typed const (rather than storage class const) immutable makes it impossible to use const references: class C { } const(C) c; if (...) c = ...; else c = ...; So, variables that are typed const are rebindable. Note that this doesn't break const, as you can always make a copy of a const. To get a non-rebindable const: const C c;
I've noticed some things that seem to be inconsistent with this behavior for local variables and where I've not found a workaround for (with the exception of casts): 1. Arrays or associative arrays of references to const instances: class C {} const(C)[] a; const(C)[string] b; It seems to be impossible here to make the array elements assignable, while at the same time keeping the class instances const. I currently need this in a function, where I'm getting a const array of instances and need to build a map to those. void fn( in C[] objs ){ const(C)[string] map; map["test"] = objs[0]; // error, not mutable } 2. Class references as members: class D { const(C) c; const C d; this( C c ){ this.c = c; // error this.d = d; // works, but, of course, only inside of the constructor } }
Nov 30 2007
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Sönke Ludwig wrote:
 I've noticed some things that seem to be inconsistent with this behavior 
 for local variables and where I've not found a workaround for (with the 
 exception of casts):
 
 
 1. Arrays or associative arrays of references to const instances:
   class C {}
   const(C)[] a;
   const(C)[string] b;
 
   It seems to be impossible here to make the array elements assignable, 
 while at the same time keeping the class instances const. I currently 
 need this in a function, where I'm getting a const array of instances 
 and need to build a map to those.
 
   void fn( in C[] objs ){
     const(C)[string] map;
     map["test"] = objs[0]; // error, not mutable
   }
 
 
 2. Class references as members:
   class D {
     const(C) c;
     const C d;
     this( C c ){
       this.c = c; // error
       this.d = d; // works, but, of course, only inside of the constructor
     }
   }
There isn't much to be done about this problem except make the implementation of the class itself const.
Dec 03 2007
parent reply =?ISO-8859-1?Q?S=F6nke_Ludwig?= writes:
Walter Bright schrieb:
 Sönke Ludwig wrote:
 I've noticed some things that seem to be inconsistent with this 
 behavior for local variables and where I've not found a workaround for 
 (with the exception of casts):


 1. Arrays or associative arrays of references to const instances:
   class C {}
   const(C)[] a;
   const(C)[string] b;

   It seems to be impossible here to make the array elements 
 assignable, while at the same time keeping the class instances const. 
 I currently need this in a function, where I'm getting a const array 
 of instances and need to build a map to those.

   void fn( in C[] objs ){
     const(C)[string] map;
     map["test"] = objs[0]; // error, not mutable
   }


 2. Class references as members:
   class D {
     const(C) c;
     const C d;
     this( C c ){
       this.c = c; // error
       this.d = d; // works, but, of course, only inside of the 
 constructor
     }
   }
There isn't much to be done about this problem except make the implementation of the class itself const.
As far as I understand it, it's currently only possible to have mutable references to const/invariant data when using local/global variables, but not inside classes/structs/arrays. Now, after playing some more, I have made some classes "invariant class C {}" (a really nice feature). I think it is absolutely _vital_ to be able to have at least arrays/maps of such classes. However, in this case it is not even possible to cast away the invariant, as it now belongs to the type C. The workarounds I've found are to make a proxy "struct CS { C c; }" and store that, or to cast the class reference to void*. But both solutions are ugly. Having said that, especially after using the system now for more than some const methods, I actually like the current system - of course with the above exception :) - and although it is of course quite different to C++'s solution, it's actually quite easy to grasp. PS: on a side note, I found that invariantness is lost in a few situations, when a const modifier is applied. Unfortunately I don't have an example at hand, will post one if I'm hitting it again.
Dec 03 2007
parent reply =?ISO-8859-1?Q?S=F6nke_Ludwig?= writes:
Sönke Ludwig schrieb:

 PS: on a side note, I found that invariantness is lost in a few 
 situations, when a const modifier is applied. Unfortunately I don't have 
 an example at hand, will post one if I'm hitting it again.
Okay one example is this: invariant class C {} class D { C c; const C getC(){ return c; } // error } gives: Error: cannot implicitly convert expression (this.c) of type const(C) to invariant(C)
Dec 03 2007
parent Walter Bright <newshound1 digitalmars.com> writes:
I'll work on this. Thanks for reporting it.
Dec 03 2007