equivariant functions

Denis Koroskin 2korden at gmail.com
Wed Oct 15 03:02:28 PDT 2008


On Wed, 15 Oct 2008 09:51:59 +0400, Bill Baxter <wbaxter at gmail.com> wrote:

>> inout(C) foo(inout(C) c, inout(B) function(inout(A) a) fn);
>>
>> In the last example, constancy of return value matches constancy of  
>> input
>> parameter.
>
> .. and inout(B), inout(A) there have that same constancy?  Or is their
> constancy unrelated?
>
> --bb

To answer this I need to take a use case and look at a concrete function  
implementation:

Case #1
-------
void testInoutFunction(inout(char[]) function(inout(char)[]) fn)
{
     char[] a1 = "hello".dup;
     a1 = fn(a1);
     writefln(a1);

     const(char)[] a2 = "hello";
     a2 = b(a2);
     writefln(a2);

     invariant(char)[] a3 = "hello";
     a3 = b(a3);
     writefln(a3);
}

inout(char)[] foo(inout(char)[] a);
testInoutFunction(&foo);

I think this is a valid use case. Note that testInoutFunction doesn't take  
any inout() params and the inout() constancy expantion doesn't take place  
at the call-time, i.e.

void testInoutFunction(inout(char[]) function(inout(char)[]) fn)

doesn't transform into one of these:
void testInoutFunction(char[] function(char[]) fn);
void testInoutFunction(const(char[]) function(const(char)[]) fn);
void testInoutFunction(invariant(char[]) function(invariant(char)[]) fn);

Adding an additional parameter doesn't change a bit (function shouldn't  
change its behaviour drastically given additional parameter):

inout(char)[] testInoutFunction(inout(char)[] a, inout(char[])  
function(inout(char)[]) fn)
{
     testInoutFunction(fn); // call zero-arg version
     // do something with a
     return a[1..$];
}

So a rule here is that inout() constancy expansion  doesn't take place for  
delegate and function pointers.

Case #2
-------

In this case, inout() constancy expantion does take place on delegates and  
function pointers. Let's see if it is useful:

char[] foo1(char[] a);
invariant(char)[] foo2(invariant(char)[] a);

void testInoutFunction(inout(char[]) function(inout(char)[]) fn);

testInoutFunction(&foo1); // assume, we wanna call like this
testInoutFunction(&foo2); // and like this

Given these uses cases, what assumptions can testInoutFunction make and  
actions take?

void testInoutFunction(inout(char[]) function(inout(char)[]) fn)
{
     char[] a = "hello".dup;
     a = fn(a); // invalid, violates foo2 typechecking

     invariant(char)[] b = "hello";
     b = fn(b); // invalid, violates foo1 typechecking

     const(char)[] c = "hello";
     c = fn(c); // ok
}

See, testInoutFunction's actually can't do much. In fact it is no  
different from
void testInoutFunction(const(char)[] function(char(char)[]) fn);

So the second use case is in fact incorrect and should not be allowed.

Back to the original example:
> inout(C) foo(inout(C) c, inout(B) function(inout(A) a) fn);

Type of return value here depends on type of first argument (c), type of  
fn doesn't vary, it is always the same.



More information about the Digitalmars-d mailing list