inout and function/delegate parameters

kenji hara at
Sun Feb 19 14:27:00 PST 2012

I think the 'scope' keyword may resolve issue.

Attributes of lazy parameter in template function belong to caller side.

int foo()(lazy int value) @safe pure /*nothrow*/ { return value(); }
void main() {
    int n = foo(10);
    // evaluating lazy parameter never break safety and purity of foo.
    // (violating nowthrow-ness might be a bug.)
    // because the violation belongs to caller side - it is main function.

Similarly, scope delegate body always in caller side, so calling it
means temporary exiting to caller side.

void foo(ref inout int x, scope void delegate(ref inout(int)) dg) {
void main() {
    int a;
    foo(a, (ref int x){ x = 10; });  // don't break foo's inout-ness,
so should be allowed
    assert(a == 10);

How about?

Kenji Hara

2012/2/19 Stewart Gordon <smjg_1998 at>:
> At the moment, if a function has an inout parameter, it must have an inout
> return type.
> But this prevents doing stuff like
>    void test(ref inout(int)[] x, inout(int)[] y) {
>        x = y;
>    }
> or passing the constancy through to a delegate instead of a return value.
> A typical use case of the latter is to define an opApply that works
> regardless of the constancy of this and allows the delegate to modify the
> iterated-through objects _if_ this is mutable.
>    int opApply(int delegate(ref inout(T)) dg) inout;
> But then I realised a potential ambiguity:
> (a) the constancy is passed through to the delegate
> (b) the delegate has an inout parameter in its own right
> If we go by interpretation (b), then each signature contains only one inout,
> so even if we relaxed the rules to allow this it would just be equivalent to
>    int opApply(int delegate(ref const(T)) dg) const;
> however, this won't always be true in the general case.
> The essence of functions with inout parameters is that they have a hidden
> constancy parameter.  This is essentially a template parameter, except that
> only one instance of the function is generated, rather like Java generics.
>  If we made this parameter explicit in the code, we could distinguish the
> two meanings:
> (a) int opApply(constancy K)(int delegate(ref K(T)) dg) K;
> (b) int opApply(constancy K)(int delegate(constancy L)(ref L(T)) dg) K;
> Moreover, in case (a), opApply would accept for dg:
> - an int delegate(ref T) only if this is mutable
> - an int delegate(ref immutable(T)) only if this is immutable
> - an int delegate(ref const(T)), or a delegate that is itself
> constancy-templated, regardless of the constancy of this
> Perhaps the simplest example where meaning (b) is actually useful is
>    inout(char)[] process(inout(char)[] delegate(inout(char)[]) dg,
> inout(char[]) text) {
>        return text;
>    }
> but still, somebody might want meaning (a).  Anyway, under DMD 2.058 (Win32)
> this gives
> inout_delegate.d(1): Error: inout must be all or none on top level for
> inout(char)[](inout(char)[] function(inout(char)[]) fn, inout(char[]) text)
> but why?  At least it seems that DMD acknowledges the ambiguity, even if the
> error message doesn't make sense.
> The question really is: When inout is applied both to a parameter in a
> function's signature and to something in the signature of a
> function/delegate parameter therewithin, how should it be interpreted?  The
> spec doesn't seem to address the issue at all.  Indeed, we can ask two
> things:
> - what actually does the compiler make of it at the moment?
> - what would be the ideal way for it to work?
> Possibilities I can see:
> - always (a)
> - always (b)
> - (a) if at either level inout only occurs once, otherwise (b) (probably
> undesirable because of fragility)
> - just reject such signatures as ambiguous
> And moreover, should we support some syntax (similar to what I've used here
> or otherwise) to state explicitly whether we want to pass the constancy
> through to the delegate signature or not?
> Stewart.

More information about the Digitalmars-d mailing list