Thread overview
Template alias parameters to local variables
Sep 13, 2014
Marc Schütz
Sep 14, 2014
Kagamin
Sep 14, 2014
Marc Schütz
Sep 17, 2014
Marc Schütz
September 13, 2014
Consider the following code:

      alias Sink = scope void delegate(const(char)[]);

      private template generateAliases(int __i, __vars...) {
          import std.conv : to;

          static if(__i < __vars.length)
              enum generateAliases = "alias " ~
__vars[__i].stringof ~ " =
                   __vars[" ~ __i.to!string ~ "];\n" ~
                   generateAliases!(__i+1, __vars);
          else
              enum generateAliases = "";
      }

      template render(string __tpl, __vars...) {
          void render(Sink sink) {
              static void render2(string __tpl2, __vars2...)(Sink
sink2 = sink) {
                  .render!(__tpl2, __vars2)(sink2);
              }
              void render3(string __tpl2, __vars2...)(Sink sink2 =
sink) {
                  .render!(__tpl2, __vars2)(sink2);
              }

              alias __sink = sink;

              mixin(generateAliases!(0, __vars));
              //mixin(generateRenderer(__tpl));

              alias x = __vars[0];
              alias y = __vars[1];
			
              render2!("...", x, y);    // ERROR
              render3!("...", x, y);    // ERROR
          }
      }

      void main() {
          import std.stdio;
          int a, b;
          render!("...", a, b)(s => write(s));
      }

Inside the `render` function, which takes a string and several
variables as template parameters, as well as a delegate as
runtime parameter, I want another function to be available, which
should again accept a string and several aliases (including some
that `render` previously received as aliases). At the same time,
the function should implicitly pick up the sink that has been
passed to `render`. I'm trying to slightly different
implementations, `render2` and `render3`. They both produce
compile errors:

render2:
test.d(16): Error: static function test.main.render!("...", a,
b).render2 cannot access frame of function D main
test.d(29): Error: static function test.main.render!("...", a,
b).render2 cannot access frame of function D main

render3:
test.d(30): Error: template instance render3!("...", a, b) cannot
use local 'a' as parameter to non-global template render3(string
__tpl2, __vars2...)(Sink sink2 = sink)

I would prefer `render2`, because it is static and thus doesn't
need to allocate a context for the sink. Indeed, it used to
work before this issue was fixed:
https://issues.dlang.org/show_bug.cgi?id=11946
https://github.com/D-Programming-Language/dmd/pull/3884

Now, has this fix gone too far? On first glance, the `render2`
error message seems to make sense, but why doesn't the same error
occur for `render`?

However, why doesn't at least `render3` work? It's strange local
templates cannot accept local variables as aliases...

Alternatively, does anyone know of another way to achieve what I
want?
September 14, 2014
Doesn't this cause infinite recursion?
September 14, 2014
On Sunday, 14 September 2014 at 09:29:16 UTC, Kagamin wrote:
> Doesn't this cause infinite recursion?

No, because the inner templates are instantiated with different first template parameters. Even if all template parameters were the same, it would only be a runtime recursion.
September 17, 2014
On Saturday, 13 September 2014 at 11:34:01 UTC, Marc Schütz wrote:
> Consider the following code:
>
>       alias Sink = scope void delegate(const(char)[]);
>
>       private template generateAliases(int __i, __vars...) {
>           import std.conv : to;
>
>           static if(__i < __vars.length)
>               enum generateAliases = "alias " ~
> __vars[__i].stringof ~ " =
>                    __vars[" ~ __i.to!string ~ "];\n" ~
>                    generateAliases!(__i+1, __vars);
>           else
>               enum generateAliases = "";
>       }
>
>       template render(string __tpl, __vars...) {
>           void render(Sink sink) {
>               static void render2(string __tpl2, __vars2...)(Sink
> sink2 = sink) {
>                   .render!(__tpl2, __vars2)(sink2);
>               }
>               void render3(string __tpl2, __vars2...)(Sink sink2 =
> sink) {
>                   .render!(__tpl2, __vars2)(sink2);
>               }
>
>               alias __sink = sink;
>
>               mixin(generateAliases!(0, __vars));
>               //mixin(generateRenderer(__tpl));
>
>               alias x = __vars[0];
>               alias y = __vars[1];
> 			
>               render2!("...", x, y);    // ERROR
>               render3!("...", x, y);    // ERROR
>           }
>       }
>
>       void main() {
>           import std.stdio;
>           int a, b;
>           render!("...", a, b)(s => write(s));
>       }
>
> Inside the `render` function, which takes a string and several
> variables as template parameters, as well as a delegate as
> runtime parameter, I want another function to be available, which
> should again accept a string and several aliases (including some
> that `render` previously received as aliases). At the same time,
> the function should implicitly pick up the sink that has been
> passed to `render`. I'm trying to slightly different
> implementations, `render2` and `render3`. They both produce
> compile errors:
>
> render2:
> test.d(16): Error: static function test.main.render!("...", a,
> b).render2 cannot access frame of function D main
> test.d(29): Error: static function test.main.render!("...", a,
> b).render2 cannot access frame of function D main
>
> render3:
> test.d(30): Error: template instance render3!("...", a, b) cannot
> use local 'a' as parameter to non-global template render3(string
> __tpl2, __vars2...)(Sink sink2 = sink)
>
> I would prefer `render2`, because it is static and thus doesn't
> need to allocate a context for the sink. Indeed, it used to
> work before this issue was fixed:
> https://issues.dlang.org/show_bug.cgi?id=11946
> https://github.com/D-Programming-Language/dmd/pull/3884
>
> Now, has this fix gone too far? On first glance, the `render2`
> error message seems to make sense, but why doesn't the same error
> occur for `render`?
>
> However, why doesn't at least `render3` work? It's strange local
> templates cannot accept local variables as aliases...
>
> Alternatively, does anyone know of another way to achieve what I
> want?

Anyone an idea?