The patch https://github.com/D-Programming-Language/dmd/pull/558 implements the two phases of inout resolution.
Until merging of it, I'll not post a patch to relax inout rule. Kenji Hara 2011/12/13 Steven Schveighoffer <[email protected]>: > 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
