Thread overview
cannot use local f as parameter to non-global template
Dec 08, 2018
aliak
Dec 08, 2018
Paul Backus
Dec 10, 2018
aliak
Dec 10, 2018
Paul Backus
December 08, 2018
Hi, I'm wondering about why this happens in a certain situation and not another. I have the following code:

struct Holder(alias fun) {
    alias T = typeof(fun());
    T get() { return fun(); }
    alias get this;
}

template match(handlers...) {
    auto match(T)(T holder) {
        return handlers[0](holder);
    }
}

void main() {
    int f() { return i7 }
    auto value = Holder!f().match!(
        (int a) => f()
    );
}

This compiles fine. However, if I change the match template to:

template match(handlers...) {
    auto match(alias f)(Holder!f holder) {
        return handlers[0](holder);
    }
}

Notice the template parameter of the eponymous match is an alias now, and the function parameter is typed as a Holder.

The error you get is basically because of bug 5710 [0] I guess. But I'm confused as to why the same thing doesn't then happen when using match(T) as opposed to match(alias f)?

I can work around it by have a template constraint on match of course. But still curious why one version works and the other not, they both have to access the same frame+context data at the end of the day.


[0]: https://issues.dlang.org/show_bug.cgi?id=5710
December 08, 2018
On Saturday, 8 December 2018 at 09:57:29 UTC, aliak wrote:
> This compiles fine. However, if I change the match template to:
>
> template match(handlers...) {
>     auto match(alias f)(Holder!f holder) {
>         return handlers[0](holder);
>     }
> }
>
> Notice the template parameter of the eponymous match is an alias now, and the function parameter is typed as a Holder.

The "de-sugared" version of your second `match` function looks like this:

template match(handlers...) {
    template match(alias f) {
        auto match(Holder!f holder) {
            return handlers[0](holder);
        }
    }
}

Notice the second template nested inside the first. That's the "non-gloal template" the error is complaining about.
December 10, 2018
On Saturday, 8 December 2018 at 14:21:01 UTC, Paul Backus wrote:
> On Saturday, 8 December 2018 at 09:57:29 UTC, aliak wrote:
>> This compiles fine. However, if I change the match template to:
>>
>> template match(handlers...) {
>>     auto match(alias f)(Holder!f holder) {
>>         return handlers[0](holder);
>>     }
>> }
>>
>> Notice the template parameter of the eponymous match is an alias now, and the function parameter is typed as a Holder.
>
> The "de-sugared" version of your second `match` function looks like this:
>
> template match(handlers...) {
>     template match(alias f) {
>         auto match(Holder!f holder) {
>             return handlers[0](holder);
>         }
>     }
> }
>
> Notice the second template nested inside the first. That's the "non-gloal template" the error is complaining about.

Ah, that's a good way of breaking it down. But ok, so then the other version would be lowered to:

template match(handlers...) {
    template match(T) {
        auto match(T holder) {
            return handlers[0](holder);
        }
    }
}

So now the second template is accessing a T, which is actually a Holder!f right? But doing that makes it "work". Even though the number of "contexts" needed to execute "handlers[0](holder)" is the same, right?
December 10, 2018
On Monday, 10 December 2018 at 16:15:36 UTC, aliak wrote:
>
> Ah, that's a good way of breaking it down. But ok, so then the other version would be lowered to:
>
> template match(handlers...) {
>     template match(T) {
>         auto match(T holder) {
>             return handlers[0](holder);
>         }
>     }
> }
>
> So now the second template is accessing a T, which is actually a Holder!f right? But doing that makes it "work". Even though the number of "contexts" needed to execute "handlers[0](holder)" is the same, right?

Holder!f is a type, not a delegate, so passing it as a parameter to a non-global template is fine. Issue 5710 only applies to delegates passed directly as parameters.

Trying to reason about the "number of contexts" required is a waste of time. There's no logical, principled reason why one works and the other doesn't. It's purely an artifact of details in the compiler implementation.