www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - const in dmd v2.011

reply Derek Parnell <derek nomail.afraid.org> writes:
//-------- BEGIN CODE EXAMPLE ------------
class C{ int val; }

void main()
{
    // 'c' is an implied const reference to a const object
   const(C) c = new C;
   const(C) d = new C;
   
   c = d; // fails "variable test.main.c cannot modify const"
   c.val = 1; // fails "Error: cannot modify const/invariant c.val"
   
    // 'cc' is a const reference to an implied const object
   const C cc = new C;
   const C dd = new C;
   
   cc = dd; // fails "variable test.main.cc cannot modify const"
   cc.val = 1; // fails "Error: cannot modify const/invariant cc.val"
   
    // 'ccc' is a mutable reference to a mutable object
         C ccc = new C;
   const C ddd = new C;
   
   ccc = ddd; // fails "Error: cannot implicitly convert expression (ddd)
of type const(C) to test.C"
   ccc.val = 1; // allowed
   ddd = ccc; // fails "variable test.main.ddd cannot modify const"
   
   // 'e' is a const value 
   const(char) e = 'a';
   const(char) f = 'b';
   
   f = e; // fails "variable test.main.f cannot modify const"
   
   // 'g' is a mutable reference to an array of const data
   const(char)[] g = "abc";
   const(char)[] h = "xyz";
   
   h = g; // Allowed!!!
   h[0] = 'A'; // fails "Error: h[0] is not mutable"
   
   // 'gg' is a const reference to an array of const data
   const const(char)[] gg = "abc";
   const const(char)[] hh = "xyz"; // fails?? " Error: hh[0] is not
mutable"
   
   hh = gg; // fails "variable test.main.hh cannot modify const"
   hh[0] = 'A'; // fails "Error: constant hh[0] is not an lvalue"???
   
   // ??? 'i' is a const reference to an array of const data ???
   const(char[]) i = "abc"; 
   const(char[]) j = "xyz"; // ?? FAILS "Error: j[0] is not mutable"
   
   j = i; // fails "variable test.main.j cannot modify const"
   j[0] = 'A'; // fails "Error: constant j[0] is not an lvalue" ????
   
}
//------------ END CODE EXAMPLE ------------


Observations:
** It appears that there is no practical difference between 'const(C) c'
and 'const C c'.

** It appears that 'const(char[])' and 'const const(char)[]' are equivalent
and also not implemented well (or the error messages are just bad).

** The addition of '[]' changes the meaning of the syntax form 'const(x)
y'. Specifically 'const(x) y' means that the bits in 'y' are immutable but
'const(x)[] y' means that the bits in 'y' are mutable.

** The current implementation of const in dmd v2.011 is definitely
confusing, and is not as regular/orthogonal as I expected it to be.

** There are some access permutations that are not possible without
deceiving the compiler. This has got to be a bad thing for maintenance
costs.

-- 
Derek
(skype: derek.j.parnell)
Melbourne, Australia
21/02/2008 10:11:53 AM
Feb 20 2008
parent reply Jason House <jason.james.house gmail.com> writes:
It seems like you may have read some very early D 2.x docs on const and not
read the later D 2.x docs.  The const design has changed a lot.

Derek Parnell wrote: 
 Observations:
 ** It appears that there is no practical difference between 'const(C) c'
 and 'const C c'.
This is the definition of transitive const.
 ** It appears that 'const(char[])' and 'const const(char)[]' are
 equivalent and also not implemented well (or the error messages are just
 bad).
const(char)[] means the char's within the array can't be changed, but the array itself can change (ie. length changes, concatenation)
Feb 20 2008
parent reply Derek Parnell <derek nomail.afraid.org> writes:
On Wed, 20 Feb 2008 19:03:56 -0500, Jason House wrote:

 It seems like you may have read some very early D 2.x docs on const and not
 read the later D 2.x docs.  The const design has changed a lot.
Thanks Jason. I know that keeping up with the changes in const theory and practice is a full time job in itself ;-) but I had been aware of these later tweaks.
 Derek Parnell wrote: 
 Observations:
 ** It appears that there is no practical difference between 'const(C) c'
 and 'const C c'.
This is the definition of transitive const.
Yes it is. What I was bring to attention is the potentially confusing syntax options that are now available.
 ** It appears that 'const(char[])' and 'const const(char)[]' are
 equivalent and also not implemented well (or the error messages are just
 bad).
const(char)[] means the char's within the array can't be changed, but the array itself can change (ie. length changes, concatenation)
Yes, I know what it means. Again what I'm bring attention to is the confusing nature of this syntax. const(char) X; // 'X' is const. const(char)[] X; // 'X' is not const. also this ... const(char)* k; // 'k' is a mutable pointer to immutable data. const(char*) l; // 'l' is an immutable pointer to immutable data. The forms 'const(char)[]' and 'const(char)*' ignore transitivity while other forms enforce it. It could be confusing, no? Also the forms 'const const(X)[]', 'const const(X[])', and 'const(X[])' appear to be synonymous, another way to confuse people. -- Derek (skype: derek.j.parnell) Melbourne, Australia 21/02/2008 11:22:35 AM
Feb 20 2008
next sibling parent Jesse Phillips <jessekphillips gmail.com> writes:
On Thu, 21 Feb 2008 11:44:14 +1100, Derek Parnell wrote:

 On Wed, 20 Feb 2008 19:03:56 -0500, Jason House wrote:
 
 It seems like you may have read some very early D 2.x docs on const and
 not read the later D 2.x docs.  The const design has changed a lot.
Thanks Jason. I know that keeping up with the changes in const theory and practice is a full time job in itself ;-) but I had been aware of these later tweaks.
 Derek Parnell wrote:
 Observations:
 ** It appears that there is no practical difference between 'const(C)
 c' and 'const C c'.
This is the definition of transitive const.
Yes it is. What I was bring to attention is the potentially confusing syntax options that are now available.
 ** It appears that 'const(char[])' and 'const const(char)[]' are
 equivalent and also not implemented well (or the error messages are
 just bad).
const(char)[] means the char's within the array can't be changed, but the array itself can change (ie. length changes, concatenation)
Yes, I know what it means. Again what I'm bring attention to is the confusing nature of this syntax. const(char) X; // 'X' is const. const(char)[] X; // 'X' is not const. also this ... const(char)* k; // 'k' is a mutable pointer to immutable data. const(char*) l; // 'l' is an immutable pointer to immutable data. The forms 'const(char)[]' and 'const(char)*' ignore transitivity while other forms enforce it. It could be confusing, no? Also the forms 'const const(X)[]', 'const const(X[])', and 'const(X[])' appear to be synonymous, another way to confuse people.
Personally the const(char)* and const(char)[] make sense in their meaning. Not too the definition given of transivity: "transitive, which means that any data reachable through an invariant reference is also invariant, and likewise for const." The use of the word reference shows that it does not apply to pointers. This however is confusing to those that do not see a difference, I do it my self at times.
Feb 20 2008
prev sibling next sibling parent Jason House <jason.james.house gmail.com> writes:
Derek Parnell wrote:

 On Wed, 20 Feb 2008 19:03:56 -0500, Jason House wrote:
 
 It seems like you may have read some very early D 2.x docs on const and
 not
 read the later D 2.x docs.  The const design has changed a lot.
Thanks Jason. I know that keeping up with the changes in const theory and practice is a full time job in itself ;-) but I had been aware of these later tweaks.
 Derek Parnell wrote:
 Observations:
 ** It appears that there is no practical difference between 'const(C) c'
 and 'const C c'.
This is the definition of transitive const.
Yes it is. What I was bring to attention is the potentially confusing syntax options that are now available.
I don't see the confusion. I've previously argued that "const(C) c" and "const C c" should mean the same thing. The whole distinction between a type and a storage class seemed foreign and strange to me.
 ** It appears that 'const(char[])' and 'const const(char)[]' are
 equivalent and also not implemented well (or the error messages are just
 bad).
const(char)[] means the char's within the array can't be changed, but the array itself can change (ie. length changes, concatenation)
Yes, I know what it means.
Sorry. It's tough to know what people know, and it's usually best to elimate the simple stuff first ;)
 Again what I'm bring attention to is the 
 confusing nature of this syntax.
 
    const(char)   X; // 'X' is const.
    const(char)[] X; // 'X' is not const.
 
 also this ...
 
    const(char)* k; // 'k' is a mutable pointer to immutable data.
    const(char*) l; // 'l' is an immutable pointer to immutable data.
 
 The forms 'const(char)[]' and 'const(char)*' ignore transitivity while
 other forms enforce it. It could be confusing, no?
I've already admitted that I'm biased :) It seems easy to explain to me: * Anything inside parenthesis is constant * Const is transitive. Any data access through a const reference is const. * "const T t" is the same as "const(T) t"
 Also the forms 'const const(X)[]', 'const const(X[])', and 'const(X[])'
 appear to be synonymous, another way to confuse people.
I totally agree with that. Literally typed like that seems like it should be illegal. I can imagine complex cases where something like that should be legal... eg: alias const(X) Y; const Y z;
Feb 20 2008
prev sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Derek Parnell" wrote
 On Wed, 20 Feb 2008 19:03:56 -0500, Jason House wrote:

 It seems like you may have read some very early D 2.x docs on const and 
 not
 read the later D 2.x docs.  The const design has changed a lot.
Thanks Jason. I know that keeping up with the changes in const theory and practice is a full time job in itself ;-) but I had been aware of these later tweaks.
 Derek Parnell wrote:
 Observations:
 ** It appears that there is no practical difference between 'const(C) c'
 and 'const C c'.
This is the definition of transitive const.
Yes it is. What I was bring to attention is the potentially confusing syntax options that are now available.
To address this point, let me show you why. 5 + 2 is equivalent to (5 + 2) The parentheses add nothing, but are not illegal. Similarly const(C) is equivalent to const C The parentheses add nothing. However, 5 + 2 * 3 is not equivalent to (5 + 2) * 3 Because now the parentheses are telling the compiler which operation comes first. Similarly: const C * is not equivalent to const(C) * The parentheses are defining the scope of the const statement.
 ** It appears that 'const(char[])' and 'const const(char)[]' are
 equivalent and also not implemented well (or the error messages are just
 bad).
I think some of the issues you point out, especially where you have 2 seemingly similar statements where one statement gives an error and the other does not, are real bugs that should be filed. However, you need to realize that in order to support generic const-ification, this kind of syntax needs to be supported. For example, if you have a type T, and you want a const version, you can do: const T t; However, what if T is an alias for const(C)? Now, const T is equivalent to const const(C), and that reduces to const(C), which is necessary to allow for the type system to work. If const const(C) was different than const(C), then the type assignment would be all screwed up. Similarly, if you don't allow const const(C) because the const is redundant, then you can't const-ify any type by doing const T because then generic programming gets really ugly, with lots of static ifs. I think the way it works is the way it should.
 const(char)[] means the char's within the array can't be changed, but the
 array itself can change (ie. length changes, concatenation)
Yes, I know what it means. Again what I'm bring attention to is the confusing nature of this syntax. const(char) X; // 'X' is const. const(char)[] X; // 'X' is not const.
Again, this is the scoping of the parentheses limit the scope of const to the array elements. If you have the generic type: struct S(T) { T[] x; } Now, if you do S!(const(char)) c; S!(char) m; S is defining a mutable array of T's, clearly from the declaration. Even in c, you can mutate the x array without affecting any data that x points to, thus not violating const rules. To prohibit this would be counter-productive, and cause lots of headaches. The goal of the const system should be not only to ensure const data doesn't change, but should also be to ensure non-const data CAN be changed.
 also this ...

   const(char)* k; // 'k' is a mutable pointer to immutable data.
   const(char*) l; // 'l' is an immutable pointer to immutable data.
Same thing. The parentheses limit the scope of const.
 The forms 'const(char)[]' and 'const(char)*' ignore transitivity while
 other forms enforce it. It could be confusing, no?
This is not so, they do not ignore transitivity. Transitivity means that if you have a pointer to const data, anything that data points to must also be const. If the array was const but the data pointed to could be changed through the array pointer, then transitivity would be broken. -Steve
Feb 20 2008
next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Steven Schveighoffer" wrote
 The forms 'const(char)[]' and 'const(char)*' ignore transitivity while
 other forms enforce it. It could be confusing, no?
This is not so, they do not ignore transitivity. Transitivity means that if you have a pointer to const data, anything that data points to must also be const. If the array was const but the data pointed to could be changed through the array pointer, then transitivity would be broken.
I didn't say this right. What I meant was Transitivity means that if you have a pointer who defines itself as pointing to const data, any data that you access through that pointer, whether it be the data the pointer points to, or data pointed to by the const data, must be const. For example: int z = 1; int * y = &z; const(int*)* x = &y; writefln(**x); // outputs 1, this is ok because i'm just reading the data, not modifying *y = 2; writefln(**x); // outputs 2, still ok, because I'm not modifying **x = 3; // not ok, even though y isn't const, I'm trying to modify what y points to *through* x. I hope this helps. -Steve
Feb 20 2008
prev sibling parent reply Derek Parnell <derek nomail.afraid.org> writes:
On Wed, 20 Feb 2008 22:39:03 -0500, Steven Schveighoffer wrote:

 I think some of the issues you point out, especially where you have 2 
 seemingly similar statements where one statement gives an error and the 
 other does not, are real bugs that should be filed.
After a bit more examination, it is probably not a bug but just a poor error message. It turns out that const(char[]) s = "abc"; is essentially treated as a manifest constant. It is almost identical to enum (s = "abc"} The person who can document all this 'const' implementation so that most people can grasp it and remember it, will win lots of brownie points. -- Derek (skype: derek.j.parnell) Melbourne, Australia 21/02/2008 5:42:22 PM
Feb 20 2008
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Derek Parnell"  wrote
 On Wed, 20 Feb 2008 22:39:03 -0500, Steven Schveighoffer wrote:

 I think some of the issues you point out, especially where you have 2
 seemingly similar statements where one statement gives an error and the
 other does not, are real bugs that should be filed.
After a bit more examination, it is probably not a bug but just a poor error message. It turns out that const(char[]) s = "abc"; is essentially treated as a manifest constant. It is almost identical to enum (s = "abc"}
Well, the lines I was thinking of were (from your original post): const(char[]) i = "abc"; const(char[]) j = "xyz"; // ?? FAILS "Error: j[0] is not mutable" Why does i work, but j does not? Both lines seem identical in syntax. Besides that, a string (which is an invariant(char)[]) should be assingable to a const, because you can implicitly cast the mutable array to a const array, and implictly cast an invariant char to a const char (for the element type). So I would expect both i and j to compile.
 The person who can document all this 'const' implementation so that most
 people can grasp it and remember it, will win lots of brownie points.
I think the tough part to grasp right now is the 'why' not the 'how'. Once people stop debating the why part, the how becomes as simple as a set of examples and explanation of how to use it. -Steve
Feb 21 2008
parent reply Derek Parnell <derek psych.ward> writes:
On Thu, 21 Feb 2008 09:05:15 -0500, Steven Schveighoffer wrote:

 "Derek Parnell"  wrote
 On Wed, 20 Feb 2008 22:39:03 -0500, Steven Schveighoffer wrote:

 I think some of the issues you point out, especially where you have 2
 seemingly similar statements where one statement gives an error and the
 other does not, are real bugs that should be filed.
After a bit more examination, it is probably not a bug but just a poor error message. It turns out that const(char[]) s = "abc"; is essentially treated as a manifest constant. It is almost identical to enum (s = "abc"}
Well, the lines I was thinking of were (from your original post): const(char[]) i = "abc"; const(char[]) j = "xyz"; // ?? FAILS "Error: j[0] is not mutable" Why does i work, but j does not? Both lines seem identical in syntax.
They are identical but the compiler is a bit too smart. The first one compiles without complaint because the 'manifest' constant it declares is never actually used so it optimizes it out of the picture. The second ones 'fails' to compile because I attempt to use 'j' as an lvalue later on. The error message is very misleading, but accurate too. -- Derek Parnell Melbourne, Australia skype: derek.j.parnell
Feb 21 2008
parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Derek Parnell" wrote
 On Thu, 21 Feb 2008 09:05:15 -0500, Steven Schveighoffer wrote:
 Well, the lines I was thinking of were (from your original post):
 const(char[]) i = "abc";
 const(char[]) j = "xyz"; // ?? FAILS "Error: j[0] is not mutable"

 Why does i work, but j does not?  Both lines seem identical in syntax.
They are identical but the compiler is a bit too smart. The first one compiles without complaint because the 'manifest' constant it declares is never actually used so it optimizes it out of the picture. The second ones 'fails' to compile because I attempt to use 'j' as an lvalue later on. The error message is very misleading, but accurate too.
Ah... no this is not the case :) You are attempting to use j as an lvalue later on. that is what causes the error. If you used j as an rvalue, then the compiler would not complain. I think the problem here is that you are interpreting the compiler error as saying "line X failed to compile, j[0] is not mutable", when it really is saying "j[0] is not mutable because it was declared that way on line X". I guess it's really just a confusing error message. -Steve
Feb 21 2008