Proposal - Revised Syntax for const and final

Reiner Pope some at address.com
Sat Sep 8 21:04:11 PDT 2007


Reiner Pope wrote:
> Janice Caron wrote:
>> The fact that
>> const(int**) s;
>> const(int*)* s;
>> both mean the same thing is highly counterintuitive.
> 
> I agree. However, I think this problem can be solved with much smaller
> changes.
> 
> The syntax would be consistent if const(T) was a type constructor which 
> gave a type like T, but with tail const. Consider the struct A, defined 
> below:
> 
> struct A
> {
>     int x;
> }
> 
> The types const(A) and A should behave identically, as there is no 
> "tail" to be made constant. The following code is valid:
> 
> const(A) a;
> a.x = 5; // nothing wrong here
> 
> Now consider the array type constructor, [], which takes a type T and 
> returns the array type T[]. For this to be a sensible type constructor, 
> any operation permitted on T should be permitted on the elements of T[]. 
>   This is true of user-land type constructors (templated structs, etc) 
> but not of pointers and arrays. Consider:
> 
> struct MyArray(T)
> {
>     T firstElem;
> }
> 
> This is a valid type constructor, which takes a type T and returns an 
> array of T (admittedly, the array isn't very interesting -- it only has 
> one element -- but you can still call it an array). Now contrast the use:
> 
> const(A)[] b;
> b[0].x = 5; // error, b[0].x is not mutable
> 
> MyArray!(const(A)) c;
> c.firstElem.x = 5; // fine
> 
> 
> Now you might complain and point out that const(A)[] actually contains A 
> behind a pointer, whereas MyArray!(const(A)) stores A directly. Well, we 
> solve that problem by instead declaring MyArray as a class:
> 
> class MyArray2(T)
> {
>     T firstElem;
> }
> 
> MyArray2!(const(A)) c2;
> c2.firstElem.x = 5; // still fine
> 
> [Note that I'm showing the reference behaviour with classes and not with 
> pointers because both pointers and arrays have this "taint" that I'm 
> trying to show is inconsistent.]
> 
> 
> This is a very inconsistent behaviour. We used to have the property that 
>  any member accessible of an instance of T is also accessible of an 
> element of T[]. This is no longer true, and it means that generic code 
> may require extra special cases.
> 
> 
> The way to fix it is simply to remove the special cases, which exist for
> 
> const(T)*
> 
> and
> 
> const(T)[]
> 
> In both of these cases, the data pointed to should be tail const. 
> Currently, it is head *and* tail const.
> 
> 
> 
>    -- Reiner

I think I was a bit round-a-bout with that. Here's a simpler argument: 
for any type T, T* should mean "pointer to T". If you have

struct A
{
     int x;
     int* y;
}

then consider const(A)*. From the above definition, this should mean 
"pointer to const(A)", or in other words, "pointer to tail-const A". Yet 
experimentation clearly shows that const(A)* is not "pointer to 
tail-const A", but is actually "pointer to head- and tail-const A":

   const(A)* b;
   (*b).x = 5;    // not allowed, but should be
   *(*b).y = 6;   // shouldn't be allowed, and isn't


    -- Reiner



More information about the Digitalmars-d mailing list