Jump to page: 1 2
Thread overview
const in dmd v2.011
Feb 20, 2008
Derek Parnell
Feb 21, 2008
Jason House
Feb 21, 2008
Derek Parnell
Feb 21, 2008
Jesse Phillips
Feb 21, 2008
Jason House
Feb 21, 2008
Derek Parnell
Feb 21, 2008
Derek Parnell
February 20, 2008
//-------- 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
February 21, 2008
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)

February 21, 2008
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
February 21, 2008
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.
February 21, 2008
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;
February 21, 2008
"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


February 21, 2008
"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


February 21, 2008
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
February 21, 2008
"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


February 21, 2008
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
« First   ‹ Prev
1 2