Thread overview
non-global template fix POC WIP
Jan 22, 2019
Suleyman
Jan 26, 2019
Suleyman
Jan 27, 2019
Jonathan Marler
Jan 27, 2019
Jonathan Marler
Jan 27, 2019
Suleyman
Jan 27, 2019
Timon Gehr
Jan 29, 2019
Suleyman
Apr 12, 2019
Suleyman
January 22, 2019
Hello everyone.

I started working on a fix for the non-global template issue.
Progress at https://github.com/dlang/dmd/pull/9282

currently the following POC works:
```
struct S
{
    int m;

    auto add(alias a)(int b)
    {
        return a + m + b;
    }

    auto exec(alias f)()
    {
        f(m);
    }
}

void main()
{
    int a = 4;
    auto o = S(3);

    assert(o.add!a(2) == 4+3+2);

    auto dg = &o.add!a;
    assert(dg(7) == 4+3+7);

    int b;
    auto bSetter(int i) { b = i; }

    o.exec!bSetter();
    assert(b == 3);

    /* S.add instantiated to:

        auto add(int b)
        {
            return main.a + main.o.m + b;
        }

        thus only requires the frame pointer of `main`
    */
}
```

The strategy is to access the `this` variable through the frame pointer of the caller.
January 26, 2019
I think it's ready for use. I would appreciate it if someone can break it and produce a test case.
January 27, 2019
On Saturday, 26 January 2019 at 12:06:48 UTC, Suleyman wrote:
> I think it's ready for use. I would appreciate it if someone can break it and produce a test case.

I downloaded your branch and created this example that doesn't work:
---------------------------------------------------------

import core.stdc.stdio : printf;

struct Adder
{
    int base;
    // works
    uint addBaseCallFunc(alias func)(uint value)
    {
        return func(base + value);
    }

    // these 2 don't work
    uint willNeedThreeContextPtrs(alias func)(uint value)
    {
        int localVar = func(value);
        uint localFunc(uint subValue) { return localVar + subValue; }
        return addBaseCallFuncs!(func, localFunc)(value);
    }
    uint addBaseCallFuncs(alias func1, alias func2)(uint value)
    {
        return func2(func1(base + value));
    }
}

void main()
{
    auto adder = Adder(3);

    int offset = 6;
    uint doOffset(uint value) { return offset + value; }

    // works
    printf("%d\n", adder.addBaseCallFunc!doOffset(4));

    // need 3 context pointers (doesn't work)
    printf("%d\n", adder.willNeedThreeContextPtrs!doOffset(4));
}


January 27, 2019
On Sunday, 27 January 2019 at 18:13:49 UTC, Jonathan Marler wrote:
> On Saturday, 26 January 2019 at 12:06:48 UTC, Suleyman wrote:
>> I think it's ready for use. I would appreciate it if someone can break it and produce a test case.
>
> I downloaded your branch and created this example that doesn't work:
> ---------------------------------------------------------
>
> import core.stdc.stdio : printf;
>
> struct Adder
> {
>     int base;
>     // works
>     uint addBaseCallFunc(alias func)(uint value)
>     {
>         return func(base + value);
>     }
>
>     // these 2 don't work
>     uint willNeedThreeContextPtrs(alias func)(uint value)
>     {
>         int localVar = func(value);
>         uint localFunc(uint subValue) { return localVar + subValue; }
>         return addBaseCallFuncs!(func, localFunc)(value);
>     }
>     uint addBaseCallFuncs(alias func1, alias func2)(uint value)
>     {
>         return func2(func1(base + value));
>     }
> }
>
> void main()
> {
>     auto adder = Adder(3);
>
>     int offset = 6;
>     uint doOffset(uint value) { return offset + value; }
>
>     // works
>     printf("%d\n", adder.addBaseCallFunc!doOffset(4));
>
>     // need 3 context pointers (doesn't work)
>     printf("%d\n", adder.willNeedThreeContextPtrs!doOffset(4));
> }

Here's another one that seems to compile, but fails at runtime (it doesn't print anything):

import core.stdc.stdio : printf;

struct Adder
{
    int base;
    uint addBaseCallFuncs(alias func1, alias func2)(uint value)
    {
        return func2(func1(base + value));
    }
}

void main()
{
    auto adder = Adder(3);

    int offset = 6;
    uint doOffset1(uint value) { return offset + value; }

    void anotherFunc()
    {
        int anotherVar = 11;
        uint doOffset2(uint value) { return anotherVar + value; }
        printf("%d\n", adder.addBaseCallFuncs!(doOffset1, doOffset2)(4));
    }
}

January 27, 2019
On Sunday, 27 January 2019 at 18:13:49 UTC, Jonathan Marler wrote:

> I downloaded your branch and created this example that doesn't work:
> ...

Good catch! try again it should work now.
Thanks. Looking forward to your next case.
January 27, 2019
On 22.01.19 23:26, Suleyman wrote:
> 
> 
> I started working on a fix for the non-global template issue.

Thank you!
January 29, 2019
On Sunday, 27 January 2019 at 22:25:20 UTC, Timon Gehr wrote:
> Thank you!

The pleasure is mine. This was number one on my list of the most irritating limitations.

April 12, 2019
Hello,

I finished working on my solution I should be pretty solid now with a good number of unitests and corner cases covered. waiting for your replies.

link: https://github.com/dlang/dmd/pull/9282

I dropped the initial strategy instead I decided to use a static array of two pointer `void*[2]*` and making this one a closure variable thus it will be GC-allocated only when the function escapes.

example:
```
struct S
{
    auto func(alias a)() { ++a; }
}

void noClosure()
{
    int a;       // stack allocated
    auto s = S();
                // v implicit var `void*[2] __this;` stack allocated
    s.func!a(); // no closure made
}

void withClosure()
{
    int a;               // closure var GC allocated
    auto s = S();
                         // v implicit closure var `void*[2] __this;` GC allocated
    auto dg = &s.func!a; // closure made
}
```