Thread overview
[Issue 20116] Wrong delegate type when taking address of inout member function
[Issue 20116] Cannot return inout return value from delegate
Aug 14, 2019
Harry Vennik
Aug 15, 2019
Simen Kjaeraas
Aug 15, 2019
Harry Vennik
Aug 16, 2019
Simen Kjaeraas
Aug 16, 2019
Harry Vennik
Aug 16, 2019
Simen Kjaeraas
Dec 17, 2022
Iain Buclaw
August 14, 2019
https://issues.dlang.org/show_bug.cgi?id=20116

--- Comment #1 from Harry Vennik <htvennik@gmail.com> ---
Tested once again with an additional pragma statement in main():

void main()
{
    C c;
    pragma(msg, typeof(&c.arr));
    foo(&c.arr);
}

The pragma outputs: inout(int[]) delegate() inout nothrow @nogc @property @safe

Since the delegate's context actually gets typed as inout, foo() does in fact have an inout parameter.

--
August 15, 2019
https://issues.dlang.org/show_bug.cgi?id=20116

Simen Kjaeraas <simen.kjaras@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |simen.kjaras@gmail.com
            Summary|Cannot return inout return  |Wrong delegate type when
                   |value from delegate         |taking address of inout
                   |                            |member function

--- Comment #2 from Simen Kjaeraas <simen.kjaras@gmail.com> ---
I've updated the description to give a better description of what's actually wrong here.

The actual issue is what typeof(&c.arr) returns - it needs to reflect the constancy of c - inout makes no sense on the context of a delegate. IOW, this:

class C {
    int[] _arr;
    auto fun() inout { return _arr; }
}

static assert(is(typeof(&(new           C).fun) ==           int[]
delegate()));
static assert(is(typeof(&(new const     C).fun) == const    (int[])
delegate()));
static assert(is(typeof(&(new immutable C).fun) == immutable(int[])
delegate()));

should compile.

--
August 15, 2019
https://issues.dlang.org/show_bug.cgi?id=20116

--- Comment #3 from Harry Vennik <htvennik@gmail.com> ---
That is an interesting approach. Looks like that would fix this particular issue. But could you please elaborate on the effects of such semantic in the different, but related, case of Issue 15651?

--
August 16, 2019
https://issues.dlang.org/show_bug.cgi?id=20116

--- Comment #4 from Simen Kjaeraas <simen.kjaras@gmail.com> ---
It's not just an interesting approach - it's the *right* approach. When you call the delegate, you don't pass it a context, so you can't decide whether the result should be const or immutable at that point - the constancy is set in stone the moment you create it, so that's when the type should be decided.

Sadly, this would do nothing for issue 15651 - it's not creating a delegate from a struct or a class instance, so this change would have no impact whatsoever. 15651 is just a case where Unqual isn't doing all the things it perhaps should, or possibly a situation where inout simply breaks down.

--
August 16, 2019
https://issues.dlang.org/show_bug.cgi?id=20116

--- Comment #5 from Harry Vennik <htvennik@gmail.com> ---
The project I am working on suffers from both issues, so I just wanted to ensure solving one would not worsen the other.

Though I agree that the type is to be determined at delegate creation. But what would happen if a delegate is created from a struct or class reference that is already inout? In that case there is no way but making the context inout. Making it const would not be correct, because in that case, the return value of the delegate would also be const if the delegate returns (part of) its context.

--
August 16, 2019
https://issues.dlang.org/show_bug.cgi?id=20116

--- Comment #6 from Simen Kjaeraas <simen.kjaras@gmail.com> ---
The only case in which you should be able to make an inout delegate would be inside an inout function, with a context that is inout, and it would convert to the correct constancy upon leaving that function. Consider this code:

class C {
    int[] _arr;
    auto fun() inout {
        return _arr;
    }
    auto dgfun() inout {
        auto f = () => _arr;
        return f;
    }
}

typeof(&(new C).dgfun) should be int[] delegate() delegate(), even though the
type of f inside dgfun should be inout(int[]) delegate() inout.

There's also the case of &C.fun - taking the address of a member function
without a context. This is already messed up in D today*, but should return
inout(int[]) function(inout(C)). Thus, the constancy of the return value
depends on the context passed to the function.

* it returns inout(int[]) function() inout, which doesn't take a C in any way, shape or form, and is an almost foolproof recipe for memory corruption. It's also an inout function without a context for the inout to apply to, which is just plain broken. Don't use it unless you absolutely have to.

--
December 17, 2022
https://issues.dlang.org/show_bug.cgi?id=20116

Iain Buclaw <ibuclaw@gdcproject.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Priority|P1                          |P3

--