relax inout rules?

Steven Schveighoffer schveiguy at yahoo.com
Mon Dec 12 10:56:43 PST 2011


Currently, the rules of inout say you cannot put inout on a parameter  
without putting it on the return type as well.  This makes sense, it gives  
the compiler one place to worry about whether implicit casting rules will  
properly work.

But Timon Gehr brought up in another thread (started by Merdhad) that we  
can separate the resolution of inout from the applicability of the  
parameters.  Essentially, calling an inout function goes through two  
phases:

1. determine what inout resolves to
2. try and call the function.

inout rules don't have to change regarding resolving inout's actual  
value.  In other words, if all inout places are matched as int, immutable,  
or inout, then inout resolves to that value.  Otherwise inout resolves to  
const.

But what's different is (at least in my mind) the function call might not  
necessarily succeed even when the resolution is completed.

Take for example:

inout(int)* foo(inout(int)** a, inout(int)* b);

Now, if we call foo like this:

int a;
int b;
int* pa = &a;

foo(&pa, &b);

This means foo is called with (int **, int *).  This means inout resolves  
to mutable (no qualifier).  *NOW* we try calling foo as if it were written:

int *foo(int **a, int *b)

And it can be done.  Not only that, but there is nothing bad that could be  
happening in foo that should be disallowed by the compiler.

Now let's see what happens were we *could* do something bad:

immutable(int) c;
auto pc = &c;

foo(&pc, &b);

Now, foo is being called with (immutable(int)**, int *).  Inout resolves  
to const (due to the mix of mutable and immutable).  *NOW* we try calling  
foo as if it were written:

const(int)* foo(const(int)** a, const(int)* b);

And it *FAILS*.  This is because you cannot implicitly convert  
immutable(int)** to const(int)** (well, at least it *shouldn't* compile,  
I'm not sure if it does currently).

What this does is allow more possibilities for inout than we currently  
do.  Because inout is not now tied to returning something, we can create  
functions that have inout parameters but no inout return value.

The example we were discussing on the other thread was this:

void foo(ref inout(int)* a, inout(int)* b) { a = b;}

This would compile as long as you call with const(int)* as the first  
parameter, or if both parameters matched in constancy (i.e. both were  
immutable, both were mutable, or both were inout).

This gives us more cases where you don't have to repeat functions for the  
sake of handling different types of constancy, particularly when we have  
mutable references 2 levels deep.  I can't see anything technically wrong  
with this, can anyone else?

The one thing that I think still should be required is if you have inout  
on the return value, there *must* be an inout on a parameter.  Otherwise,  
the compiler has no idea what it should be (since we don't overload on  
return type in D).

If this ends up being viable, this is actually easier to explain than the  
current rules for inout.  We just have to make sure the rules are sound  
before doing something like this.

-Steve


More information about the Digitalmars-d mailing list