inout and function/delegate parameters

Steven Schveighoffer schveiguy at yahoo.com
Wed Mar 7 07:41:05 PST 2012


On Tue, 06 Mar 2012 05:11:34 -0500, Timon Gehr <timon.gehr at gmx.ch> wrote:

> On 03/06/2012 12:27 AM, Steven Schveighoffer wrote:
> ...
>>
>> There are two parts to inout, one is that it can be one function called
>> 3 different ways, the other is that you know it's constant during
>> function execution. Some people like that second part, even if it
>> doesn't fully guarantee everything. I.e. there's a reason people use
>> const in C++ besides it being trendy.
>>
>
> By passing a delegate that changes an inout-matched argument it is made  
> explicit that inout data may change. Technically, none of the existing  
> guarantees are lost, we just add some expressiveness to the type system.

Yes, I understand that it works.  I know that it doesn't violate  
technically any const guarantees.

In fact, I think this is valid D code:

int i;
const int *pi = &i;
int *p = cast()pi;
*p = 5; // legal because I know this points at i, and i is really mutable

But from an API point of view, I look at at inout as guaranteeing anything  
the parameter points at won't change while inside the function *using that  
parameter*.  Even though it's legal, it's disingenuous (at least as long  
as we define inout that way).

An interesting side note is that inout (if designed in this way) can allow  
the above code snippit to be modularized.

>
>
>>>
>>>> I'm not saying we cannot bend the rules to allow for this, because
>>>> clearly it doesn't violate the "true" constancy type of the data  
>>>> passed
>>>> in, but I don't think it's a straightforward change conceptually. I'm
>>>> not a compiler writer, so I don't know how this works in their minds,
>>>> I'd like to have their input.
>>>
>>> Implementation of what you propose should be quite simple. The issue
>>> is with the design, i.e. allowing both tying the inout in the delegate
>>> parameter signature to the inout in the enclosing signature and having
>>> an independent inout delegate parameter needs workable syntax.
>>
>> I think it can be done:
>>
>> 1. determine inout match based on existing rules, excluding delegate
>> parameters.
>> 2. change delegate parameter inouts to matched value.
>> 3. Use implicit delegate conversion (using contravariance) to allow
>> passing delegates of proper type.
>>
>> For example:
>>
>> void foo(inout(int)* x, void delegate(inout(int)* y) dg);
>>
>> void main()
>> {
>> int mx;
>> immutable int ix;
>> const int cx;
>>
>> void bar1(int *mp) {}
>> void bar2(immutable(int) *ip) {}
>> void bar3(const(int) *cp) {}
>> void bar4(inout(int) *iop) {}
>>
>> // inout matched as mutable due to mx, signature becomes void foo(int
>> *x, void delegate(int *y) dg);
>> foo(&mx, &bar1); // fine, direct match of both parameters
>> foo(&mx, &bar2); // not fine, immutable delegate does not implicitly
>> convert to mutable
>> foo(&mx, &bar3); // fine, const delegate can implicitly convert to  
>> mutable
>> foo(&mx, &bar4); // fine, inout delegate can implicitly convert to  
>> mutable
>>
>> // signature becomes void foo(immutable(int) *x, void
>> delegate(immutable(int) *y) dg);
>> foo(&ix, &bar1); // error
>> foo(&ix, &bar2); // ok
>> foo(&ix, &bar3); // fine, const delegate can implicitly convert to
>> immutable
>> foo(&ix, &bar4); // fine, inout delegate can implicitly convert to
>> immutable
>>
>> // signature becomes void foo(const(int) *x, void delegate(const(int)
>> *y) dg);
>> foo(&cx, &bar1); // error
>> foo(&cx, &bar2); // error
>> foo(&cx, &bar3); // ok
>> foo(&cx, &bar4); // ok
>>
>> // etc...
>> }
>
> I understand, but how would you support this use case?:
>
> inout(int)[] foo(inout(int)[] delegate(inout(int)[] dg), inout(int)[]  
> arr){
>      int[] x = dg(new int[16]);
>      immutable(int)[] y = dg(new immutable(int)[16]);
>      // ...
>      inout(int)[] z = dg(arr);
>      return foo(z,y,z);
> }

As usual, you find and poke holes in all my arguments :)  I'm thinking  
that in order to make this work we need a way to specify an inout modifier  
really represents the matched type rather than a full-fledged inout  
parameter.

This is not a good thing -- inout is already pretty weird and hard to  
understand.

Need to do some more thinking, maybe there's an easy way.

>> Note that Walter has explicitly rejected contravariance conversion for
>> delegates.
>
> That is unfortunate.
>
>> You have good persuasive skills, maybe you can help :) See
>> bug http://d.puremagic.com/issues/show_bug.cgi?id=3180 and
>> http://d.puremagic.com/issues/show_bug.cgi?id=3075
>>
>
> IIRC Kenji Hara has already started attempts to loosen the restrictions  
> regarding delegate implicit conversions. Hopefully Walter will  
> reconsider.

I hope so.  This is a vastly awesome untapped low-hanging fruit.

-Steve


More information about the Digitalmars-d mailing list