www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - cannot use local f as parameter to non-global template

reply aliak <something something.com> writes:
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
Dec 08 2018
parent reply Paul Backus <snarwin gmail.com> writes:
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.
Dec 08 2018
parent reply aliak <something something.com> writes:
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?
Dec 10 2018
parent Paul Backus <snarwin gmail.com> writes:
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.
Dec 10 2018