July 05, 2006
BCS wrote:
> Deewiant wrote:
>>
>>
>> I think there's a problem with all this "grant mutability/immutability", which
>> is that we're just degenerating into C++ with its const_cast. With it, the
>> compiler has few, if any, guarantees about the constness of anything --- it can
>> always be casted away.
> 
> Casting away mutability (unless I'm totally nuts) is always safe. Casting away immutability should never be allowed.

Exactly.  This is much of the reason for the "const as default" idea, as it makes sense to convert something to a more general representation (in this case mutable to immutable) but not vice-versa.  C++ got this backwards by making mutable the general category.


Sean
July 06, 2006
Sean Kelly wrote:
> BCS wrote:
>> Deewiant wrote:
>>>
>>>
>>> I think there's a problem with all this "grant mutability/immutability", which
>>> is that we're just degenerating into C++ with its const_cast. With it, the
>>> compiler has few, if any, guarantees about the constness of anything --- it can
>>> always be casted away.
>>
>> Casting away mutability (unless I'm totally nuts) is always safe. Casting away immutability should never be allowed.
> 
> Exactly.  This is much of the reason for the "const as default" idea, as it makes sense to convert something to a more general representation (in this case mutable to immutable) but not vice-versa.  C++ got this backwards by making mutable the general category.

And then had to add the 'mutable' keyword anyway <g>.
July 07, 2006
Const has a number of issues whether or not it is default:

1) function parameters that are reference types (what is talked about most here) being const
2) member functions being able to modify the object instance (const functions)
3) const in the return value
4) what happens if both const and non-const references to the same data are simultaneous, and one modifies through the non-const one?
5) assignment of a const reference to a non-const one, either explicitly or through a function parameter
6) what happens if one returns a const reference

One way to do it is to have const-as-type-modifier like C++, something I've tried to avoid as being excessively complex (compiler and programmer) and ugly.

Another way I've been toying with is just making the 'in' parameter storage class imply const reference:

class C { int m; }

void bar(C c) { c.m = 3; } // ok

void foo(in C c) { c.m = 3; } // error

void foo(in C c) { c = new C(); } // ok

C foo(in C c) { return c; } // ok

void foo(in C c) { bar(c); } // ok

void foo(in C c)
{   C d = c;
    d.m = 3;  // ok
}

What it provides is the most asked for characteristic of const.
July 07, 2006
Walter Bright wrote:
> Const has a number of issues whether or not it is default:
> 
> 1) function parameters that are reference types (what is talked about most here) being const
> 2) member functions being able to modify the object instance (const functions)
> 3) const in the return value
> 4) what happens if both const and non-const references to the same data are simultaneous, and one modifies through the non-const one?
> 5) assignment of a const reference to a non-const one, either explicitly or through a function parameter
> 6) what happens if one returns a const reference
> 
> One way to do it is to have const-as-type-modifier like C++, something I've tried to avoid as being excessively complex (compiler and programmer) and ugly.
> 
> Another way I've been toying with is just making the 'in' parameter storage class imply const reference:
> 
> class C { int m; }
> 
> void bar(C c) { c.m = 3; } // ok
> 
> void foo(in C c) { c.m = 3; } // error
> 
> void foo(in C c) { c = new C(); } // ok
> 
> C foo(in C c) { return c; } // ok
> 
> void foo(in C c) { bar(c); } // ok
> 
> void foo(in C c)
> {   C d = c;
>     d.m = 3;  // ok
> }
> 
> What it provides is the most asked for characteristic of const.

Er, that's great, but does it provide for const return-values? You see, the above can be handled adequately via either struct or class /right now/ ~ but their immutablity can quickly unravel when, for example, exposing content via toString() or whatever. And please don't suggest returning a .dup of the content instead.

July 07, 2006
Walter Bright wrote:
[...]
> class C { int m; }
> void bar(C c) { c.m = 3; } // ok
[...]
> 
> C foo(in C c) { return c; } // ok
> 
> void foo(in C c) { bar(c); } // ok
> 
> void foo(in C c)
> {   C d = c;
>     d.m = 3;  // ok
> }
> 

How would the last three work? IIRC, const implies that data is not accessible for writes. In the first of those three, the return value has no indication of const'ness so something like this could be done

void bad(in C c)
{
	c.m = 0;	//error
	foo(c).m = 0;	//same effect, but OK
}

The next one has the same effect, bar changes the parameter, where as the calling function isn't allowed to.

The last one again lets a function change something it shouldn't.



I feel like I'm missing something here, these seem to obvious for you to have missed. Maybe I'm looking for something other than what you are trying for.

What I want is a way to get an assurance by the compiler that a referenced value will not be changed. This would require that const references (or a non mutable ones) can never be made into a mutable references.

If I'm missing something, please point it out.
July 07, 2006
kris wrote:
> Er, that's great, but does it provide for const return-values?

No, it does not.

> You see, the above can be handled adequately via either struct or class /right now/ ~ but their immutablity can quickly unravel when, for example, exposing content via toString() or whatever. And please don't suggest returning a .dup of the content instead.

I've argued against the .dup method many times <g>.
July 07, 2006
BCS wrote:
> Walter Bright wrote:
> [...]
>  > class C { int m; }
>  > void bar(C c) { c.m = 3; } // ok
> [...]
>>
>> C foo(in C c) { return c; } // ok
>>
>> void foo(in C c) { bar(c); } // ok
>>
>> void foo(in C c)
>> {   C d = c;
>>     d.m = 3;  // ok
>> }
>>
> 
> How would the last three work?

The compiler would accept them, though I'd say it would be a bad programming practice.

> IIRC, const implies that data is not accessible for writes. In the first of those three, the return value has no indication of const'ness so something like this could be done

That's right.

> What I want is a way to get an assurance by the compiler that a referenced value will not be changed. This would require that const references (or a non mutable ones) can never be made into a mutable references.
> 
> If I'm missing something, please point it out.

You haven't missed something. The 'in' thing proposed above is not an airtight guarantee, you could call it more of a 'sieve'. It's more of a documentation aid. The compiler checking would be minimal and easily subverted.
July 07, 2006
Walter Bright wrote:
> kris wrote:
> 
>> Er, that's great, but does it provide for const return-values?
> 
> 
> No, it does not.

Well, that's what's actually needed to tighten up the contractual agreement between callee and caller. The 'inbound' cases /could/ be handled purely via aggregates, given an immutable return-type. As such, the latter would appear to be the base case. It would be nice to see the 'in' support, but it won't add any additional strength to the language.

> 
>> You see, the above can be handled adequately via either struct or class /right now/ ~ but their immutablity can quickly unravel when, for example, exposing content via toString() or whatever. And please don't suggest returning a .dup of the content instead.
> 
> 
> I've argued against the .dup method many times <g>.

Just a friendly reminder <g>
July 07, 2006
Walter Bright wrote:
> BCS wrote:
> 
>> What I want is a way to get an assurance by the compiler that a referenced value will not be changed. This would require that const references (or a non mutable ones) can never be made into a mutable references.
>>
>> If I'm missing something, please point it out.
> 
> 
> You haven't missed something. The 'in' thing proposed above is not an airtight guarantee, you could call it more of a 'sieve'. It's more of a documentation aid. The compiler checking would be minimal and easily subverted.

Uh... Uh... Please tell me that's not going to be the Final Solution?

A strong consistent const concept (IMVHO) would be a great thing for D. While the suggested use of "in" might help /some/, I don't see it being nearly as useful.

For one thing (and this is just a gut reaction) it don't seem vary extensible. I fear it might be just good enough that it won't ever get replaced with something better. Frankly, because of that, I'd rather see it left as-is or go to a highly restrictive const system than havening the "in" system be the primary const concept.
July 07, 2006
BCS wrote:
> What I want is a way to get an assurance by the compiler that a referenced value will not be changed. This would require that const references (or a non mutable ones) can never be made into a mutable references.

Hear hear :)

Just to clarify a little on the "will not be changed" aspect: an irresponsible user can subvert pretty much language with a cast() facility; trapping irresponsible behaviour should *not* be considered as part of this request. As noted before, we're not trying to cure stupidity.

Instead, we're looking for a means whereby DesignA is not /mistakenly/ subverted via pedestrian usage ~ a method in which to be more explicit about how DesignA is intended to be used, and which the compiler can accurately report upon.

Various pleadings to avoid incorrect usage from within the documentation of DesignA are hardly sufficient. And CoW is missing the necessary meta-data to understand whether a dup is required or not. Thus, there's no way to contractually enforce CoW (ignoring various concerns regarding CoW inefficiency and so on)