December 01, 2007
Janice Caron wrote:
> On 11/30/07, Jason House <jason.james.house@gmail.com> wrote:
>> Craig Black wrote:
>> Technically, I proposed the syntax.  Janice didn't like it at first but has
>> now come full circle.
> 
> That's right. I think my earlier attempt was something like
> "const(X)ref" or "ref const(X)". I came full circle and now fully
> support Craig's idea, largely because I think there may come a time in
> the future when D has C++-style references. If and when that day
> comes, "&" will be preferable to "ref" for the same reason that "*" is
> preferable to "ptr". 

Pointers can be stacked like T***.  References cannot.  The 'ref' can only ever apply to the head.  So I think a syntax with ref in front would be workable if Walter wants to go that way.  In some ways it makes more sense to put the sigil for references out in front because, for the most part, ref doesn't affect the way you use the thing.  ref T acts just like a T for most purposes, whereas T* is a quite different thing.

--bb
December 01, 2007
On 12/1/07, Jesse Phillips <jessekphillips@gmail.com> wrote:
> Based off of what you said in my other post, Walter will not change D's transitivity, Craig's proposal violates this.

Hmm... Someone's misunderstood something. I totally agree with Walter that transitive const is the right way to go.


> As a lot of the discussion
> here has suggested a solution for having a const ref with mutable data.

I don't think so. It's more about the distinction between const X and const(X). What we're after is a syntax for mutable ref to const data (not the other way round). What I'm saying is, if X is a class, then

    const X x; // fully const
    const(X) x; // fully const
    const(X)& x; // mutable ref to const data

There shall be /no/ way to specify const ref to mutable data.

Further, if X is not a class (say it's a struct or an int or something), then

    const(X)& x; // Errror - will not compile.



> So if I am correct then the real problem becomes with,
> const X x != const(X) x

Yes. I've been saying that for a long time now. const(X) must mean the same thing as const X because otherwise it's just silly.



> const TYPE * foo  // *foo immutable, foo mutable
> const(TYPE) * foo // same as above
> const(TYPE *) foo // foo and *foo immutable, but foo can be rebound

I stress again the general principle that const X must mean the same thing as const(X). Thus must be true regardless of the type of X. In particular, it must be true when X == TYPE *, and hence "const TYPE *" needs to mean the exact same thing as "const(TYPE *)".

The principles that "everything inside the brackets is const", and "if the brackets are omitted, everything is const", cause no problems /except/ for class references. Pointers are not a problem. Only for class references do we need extra syntax, and it was for this purpose that I proposed "const(X)&". (I wasn't the first person to suggest it though).


> It would appear this meets at least most of the complaints const() does not have a special meaning, everything can be achieved with one const keyword, transitivity holds, no ambiguity, everything in const() is const.

const(X) must mean the same thing as const X, for all X. Unless you have that, there will always be complaints.


> The only problem is that it would break all previous code,

D1 doesn't even /have/ const, so that's hardly true. The D2 branch is experimental, and those of us using it are full expect things to change. It's kind of the whole point of the branch.
December 01, 2007
On 12/1/07, Bill Baxter <dnewsgroup@billbaxter.com> wrote:
> Pointers can be stacked like T***.  References cannot.

You are completely correct, of course. T&& is the same type as T& (or
indeed, T&&&&&&&).

Honestly, I don't mind if we end up with a syntax of

    ref const(X) x; // mutable reference to const data

instead of

    const(X)& x; // mutable reference to const data

Either will make me happy.
December 01, 2007
On 12/1/07, Janice Caron <caron800@googlemail.com> wrote:
> On 12/1/07, Bill Baxter <dnewsgroup@billbaxter.com> wrote:
> > Pointers can be stacked like T***.  References cannot.
>
> You are completely correct, of course. T&& is the same type as T& (or
> indeed, T&&&&&&&).
>
> Honestly, I don't mind if we end up with a syntax of
>
>     ref const(X) x; // mutable reference to const data
>
> instead of
>
>     const(X)& x; // mutable reference to const data
>
> Either will make me happy.

Actually, the "ref" way is better than the "&" way. (Do I get to change my mind again?) Here's why. Imagine a time in the future when we have references to things that aren't classes - say, ints, structs, whatever. When that day comes, we'll need a way to distinguish between "assign the reference" and "assign the data". Well, the obvious syntax for that is

    x = y; // assign the data
    x ref= y; // assign the reference

Obviously, &= is already taken! :-)
December 02, 2007
On Fri, 30 Nov 2007 20:44:33 -0000, Bill Baxter <dnewsgroup@billbaxter.com> wrote:

> Janice Caron wrote:
>> Well, I'm still gunning for
>>      const (X)& x;
>>  for mutable refs to const classes. Since I come from a C++ background,
>> & means "reference of" to me, and this reads straightforwardly as "x
>> is a reference to const X".
>>  Of course, x would be a reference even /without/ the ampersand - such
>> is the nature of classes in D. But writing it explicitly allows one to
>> put it outside the brackets.
>
> I like where this is going, but my guess is that when/if Walter ever introduces reference types, the syntax for reference-to-T will be "ref T" like the parameter signature rather than C++'s  "T&".
>
> So if you're going peel off the hidden ref, I think you might should make it:
>
>      ref X x --> const ref(T) x;
> or          --> const (T)ref x;
> or          --> ref const(T) x;
>
> #3 seems pretty good to me.  But anyway no one knows what Walter will decide to do.

#2 is most similar to const(T)[] x and const(T)* x etc.

> About references generally, one big difference between C++ references and D classes is that you can't reassign a C++ reference.
>       // C++
>       int& x = y;
>       x = z;  /// error
>
> In that sense, the C++ references themselves are always 'const' (aka head-const / final).
> I seem to remember some example in Stroustrup that explained why this behavior was important.  But anyway, D's class references aren't like that, and it makes me wonder if more general D reference types in D would be like that.
>
> --bb

imo c++ should have had &r = &x to rebind r to x.
maybe d could do 'ref r = x' or 'ref r = ref x'
December 03, 2007
>  "const X" and "const(X)" must mean the same thing

Sorry if this is a stupid question, but if

const XY

means that both X and Y are const, then

const(X)Y will not be equivalent to const XY and thus

const(X) will not always be equivalent to const X

So what does everyone mean when they make this a requirement?  It seems to be a contradiction with the current approach to const. 

December 03, 2007
On 12/3/07, Craig Black <craigblack2@cox.net> wrote:
> Sorry if this is a stupid question, but if
>
> const XY
>
> means that both X and Y are const, then

But it doesn't. I don't understand what you're saying. A statement like "const XY x;" would mean that x is fully const and of type XY. A statement like "const X Y x;" just won't compile.
December 03, 2007
Janice Caron wrote:
> const(X) must mean the same thing as const X, for all X. Unless you
> have that, there will always be complaints.

Let's look at it another way. Consider a class C:

   alias const(C) CC;
   void foo(CC c, CC f)
   {
	auto d = c;
	d = f;
   }

This kind of code can be expected, and it should work. It should also work if CC is:

    alias const(int) CC;

because this can happen with metaprogramming. The insight is that, although a type can be const, it can always be copied (shallow copy) without affecting the const. If a variable is bound to a const type, being able to rebind it doesn't affect the const'ness, because it's just another copy. In other words, const'ness of types, const-correctness, etc., *only matters* for a type with references in it. You cannot undermine const-correctness by rebinding a variable that is typed as const.

Next, a storage class says something about how the variable is stored, not its type. We'd like to be able to say a variable is stored in read-only memory (even if that is only conceptual). Hence, we'd like to give it a storage class 'const' to put it in read-only memory. Pulling on that string, in order to have transitive const, using a const storage class must also make the type of the variable const, too.

Thus, we have:

	const(T) x;

which types x as having a const type, which matters only for references, and:

	const T x;

which types x as having a const type, *and* (conceptually) puts x in read-only memory after it is initialized.

I suggest writing some actual code using const. I think you'll find it is rather natural in practice. For example, nobody is going to write:

	const(int) x = 3;

when they want a compile-time constant, they'll write:

	const int x = 3;

The only time you'll see the form:

	const(T) x;

is when T is a reference type, or is an unknown type that could be a reference type. And the only reason one would write this is to protect the references, not x itself.

The natural question then, is why have:

	const(int) x;

at all? The reason is when one is deconstructing types using templates, and then reconstructing them, the const-correctness of what is being referred to must be carried along, else the const-correctness is lost.
December 03, 2007
Craig Black wrote:
> Here's another idea.  If we reverse the meaning of const(X) then we could do this:
> 
> const X x;  // all const
> const(X) x; // data const, ref mutable

This is what we have now.

> X const x; // data mutable, ref const 

This breaks transitivity of const.
December 03, 2007
Walter Bright wrote:
> Janice Caron wrote:
>> const(X) must mean the same thing as const X, for all X. Unless you
>> have that, there will always be complaints.
> 
>...[explanation snipped]
> 
> The natural question then, is why have:
> 
>     const(int) x;
> 
> at all? The reason is when one is deconstructing types using templates, and then reconstructing them, the const-correctness of what is being referred to must be carried along, else the const-correctness is lost.

Great explanation.

Any ETA on an updated const article?
I think this one is out of date since it still talks about final.
http://www.digitalmars.com/d/const.html

--bb