Why D const is annoying

Timon Gehr timon.gehr at gmx.ch
Mon Dec 12 07:21:35 PST 2011


On 12/12/2011 04:08 PM, Timon Gehr wrote:
> On 12/12/2011 03:46 PM, Timon Gehr wrote:
>> On 12/12/2011 01:50 PM, Steven Schveighoffer wrote:
>>> On Sun, 11 Dec 2011 12:07:37 -0500, Mafi <mafi at example.org> wrote:
>>>
>>>> Am 10.12.2011 21:25, schrieb Walter Bright:
>>>>> On 12/10/2011 11:03 AM, Mehrdad wrote:
>>>>>> So how are you supposed to implement opApply on a container (or e.g.
>>>>>> here, a
>>>>>> matrix)? Copy/paste the code for const- and non-const versions?
>>>>>
>>>>> Internal to a function, inout behaves like 'const'. You won't be
>>>>> able to
>>>>> modify the data. Therefore, if there is no inout in the return type,
>>>>> use
>>>>> 'const' in the parameter list instead.
>>>>>
>>>>> The purpose of inout is to transmit the 'constness' of the function
>>>>> argument type to the return type, using only one implementation of
>>>>> that
>>>>> function. That requires the function to internally regard inout as
>>>>> const.
>>>>
>>>> But what about:
>>>> void f(ref inout(int)* a, inout(int)* b) { a = b; }
>>>> This cant work with const because that would violate the const system.
>>>> I think the rule should be that either the return type must be inout
>>>> or at least one ref/out parameter.
>>>> Am I overlooking something?
>>>
>>> That was brought up during discussion on adding the feature. One of the
>>> reasons inout is viable is because a) the source and result of where the
>>> constancy flows is well defined and b) the exit point is an rvalue
>>>
>>> Allowing ref parameters fails both those rules.
>>>
>>> Consider this:
>>>
>>> void bad(ref inout(int)* a, ref inout(int)* b);
>>>
>>> which is the entry and which is the exit? Is a set to b, or b set to a?
>>>
>>> Now, also consider that you can't affect the constancy of the result,
>>> because the type of the parameter is already defined. e.g.:
>>>
>>> // note that your example shouldn't even be valid, because you can't
>>> implicitly cast through two mutable references
>>> int a;
>>> auto pa = &a;
>>> immutable int b;
>>> auto pb = &b;
>>>
>>> f(a, b);
>>>
>>> How can this affect a? its type is already decided. Compare that to:
>>>
>>> inout(int)* g(inout(int)* b) { return b;}
>>>
>>> auto pa = g(pb);
>>>
>>> clean and simple.
>>>
>>> -Steve
>>
>> This currently compiles:
>>
>> inout(void) very_bad(ref inout(int)* a, ref inout(int)* b){a = b;}
>>
>> void main(){
>> immutable int a=2;
>> int *x;
>> immutable(int)* y=&a;
>> very_bad(x,y);
>> *x=1;
>> assert(*y==a); // fail
>> }
>>
>> How does the design catch this error? Will inout** = inout** assignments
>> be disallowed?
>
> Probably it is better to catch it at the call site. But if that is
> implemented then the requirement to have inout on the return value gets
> nonsensical.

OK, got it.

What you call 'bad' should compile:

void bad(ref inout(int)* a, ref inout(int)* b);

int* x;
immutable(int)* y;
const(int)* z;

bad(x,x); // fine
bad(y,y); // fine
bad(z,z); // fine

bad(x,y); // inout is deduced to const, ergo neither x nor y convert to 
the parameter type -> compile error
bad(x,z); // now only error for x
...


The requirement of having inout on the return type should be removed for 
more expressiveness.









More information about the Digitalmars-d mailing list