www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Eponymous/anonymous mixin templates

reply "Jeffrey Tsang" <jeffrey.tsang ieee.org> writes:
I've been doing some fun template metaprogramming recently for a 
few projects, and I have to say the expressive power of mixin 
templates is quite staggering. I've noticed a strongly recurring 
pattern in my usage (mostly trying to get compile-time templated 
code generation, "parser from template args for input spec" for 
example):

A lot of the time, I use a mixin template to define exactly one 
symbol, and at instantiation I wish to use that symbol 
immediately, once.

This has a strong connection with both the eponymous template 
trick and anonymous expressions, and essentially is a combination 
of both - a templated anon expression looked up at instantiation 
site.

Currently, the standard workaround is defining a dummy name 
within the mixin template to do the work. The point of the 
eponymous trick is of course, to avoid this namespace pollution, 
or at least brainspace pollution.

The easiest solution I can think of is to create a second type of 
MixinExpression:

"mixin" "(" MixinTemplateName TemplateArguments_opt ")"

which extends the existing string mixin syntax. This expression 
gets rewritten into the symbol declared as the MixinTemplateName, 
along the lines of the eponymous trick alias, which is 
instantiated as a mixin. The mixin template contents are 
otherwise not imported into scope.

The only hypothetical ambiguity is if the mixin template itself 
resolves to a string literal, whether the result is to be 
compiled or not. However, it requires explicitly naming a mixin 
template, which is categorically different from a string, and to 
me it's completely safe to treat the result of the expression as 
a literal string symbol.

With this, an extended request/alternate solution would be to 
allow writing eponymous mixin templates as well, in the same way 
normal eponymous templates are.

What this looks to me is effectively making "mixin" a modifier 
keyword on templates in general, to bind at instantiation site 
rather than declaration site, and following all the logical 
consequences. Current TemplateMixins naturally become general 
instantiation imports, like using a normal template in a noop.
Jun 07 2015
parent reply Artur Skawina via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 06/07/15 11:05, Jeffrey Tsang via Digitalmars-d wrote:
 I use a mixin template to define exactly one symbol, and at instantiation I
wish to use that symbol immediately, once.
AFAICT you're asking for the commented-out line in auto Tmpl() = l; void main(string[] argv) { auto l = argv.length; mixin Tmpl!() a; assert(a.Tmpl==l); //assert(a==l); } to work. That would probably be enough, make sense and have no serious backward compat issues. artur
Jun 07 2015
parent reply "Jeffrey Tsang" <jeffrey.tsang ieee.org> writes:
On Sunday, 7 June 2015 at 14:17:45 UTC, Artur Skawina wrote:
 On 06/07/15 11:05, Jeffrey Tsang via Digitalmars-d wrote:
 I use a mixin template to define exactly one symbol, and at 
 instantiation I wish to use that symbol immediately, once.
AFAICT you're asking for the commented-out line in auto Tmpl() = l; void main(string[] argv) { auto l = argv.length; mixin Tmpl!() a; assert(a.Tmpl==l); //assert(a==l); } to work. That would probably be enough, make sense and have no serious backward compat issues. artur
There are three separate things I would like to have: 1. Eponymous trick mixin T foo(T)() { return bar; } as pure syntactic sugar for mixin template foo(T) { T foo() { return bar; } } 2. Eponymous trick, calling end mixin foo!T; to also include as syntactic support alias foo = foo!T.foo; as well as the named version you listed. 3. Inline/anonymous mixins Some way of writing the equivalent of bar = (mixin foo!T)() + 3; inline as an expression, the same way as bar = regular_template_foo!T() + 3;
Jun 08 2015
parent reply Artur Skawina via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 06/08/15 17:14, Jeffrey Tsang via Digitalmars-d wrote:
 On Sunday, 7 June 2015 at 14:17:45 UTC, Artur Skawina wrote:
 On 06/07/15 11:05, Jeffrey Tsang via Digitalmars-d wrote:
 I use a mixin template to define exactly one symbol, and at instantiation I
wish to use that symbol immediately, once.
AFAICT you're asking for the commented-out line in auto Tmpl() = l; void main(string[] argv) { auto l = argv.length; mixin Tmpl!() a; assert(a.Tmpl==l); //assert(a==l); } to work. That would probably be enough, make sense and have no serious backward compat issues.
There are three separate things I would like to have: 1. Eponymous trick mixin T foo(T)() { return bar; } as pure syntactic sugar for mixin template foo(T) { T foo() { return bar; } }
This part already works, if you leave out the 'mixin' annotation (which only prevents non-mixin use). "Normal" templates can be mixed in too, see my `Tmpl` example above. T foo(T)() { return bar; } auto f(int bar) { mixin foo!double blah; return blah.foo(); } void main() { assert (f(42)==42.0); }
 2. Eponymous trick, calling end
 
 mixin foo!T;
 
 to also include as syntactic support
 
 alias foo = foo!T.foo;
 
 as well as the named version you listed.
No, that would hide the `foo` template symbol. There's no such problem with the named version (other than the eponymous look-up not working).
 3. Inline/anonymous mixins
 
 Some way of writing the equivalent of
 
 bar = (mixin foo!T)() + 3;
This part I'm not sure about. Can't think of an interesting use case, that wouldn't be better handled in some other way. The obvious workaround would be: bar = { mixin foo!T f; return f()+3; }(); // today: `f.foo()+3` [`{...}()` might result in a lambda/closure right now, but that should really be fixed (ie defined as a special case)] artur
Jun 08 2015
parent reply "Jeffrey Tsang" <jeffrey.tsang ieee.org> writes:
On Monday, 8 June 2015 at 16:27:36 UTC, Artur Skawina wrote:
 On 06/08/15 17:14, Jeffrey Tsang via Digitalmars-d wrote:
 On Sunday, 7 June 2015 at 14:17:45 UTC, Artur Skawina wrote:
 On 06/07/15 11:05, Jeffrey Tsang via Digitalmars-d wrote:
 I use a mixin template to define exactly one symbol, and at 
 instantiation I wish to use that symbol immediately, once.
AFAICT you're asking for the commented-out line in auto Tmpl() = l; void main(string[] argv) { auto l = argv.length; mixin Tmpl!() a; assert(a.Tmpl==l); //assert(a==l); } to work. That would probably be enough, make sense and have no serious backward compat issues.
There are three separate things I would like to have: 1. Eponymous trick mixin T foo(T)() { return bar; } as pure syntactic sugar for mixin template foo(T) { T foo() { return bar; } }
This part already works, if you leave out the 'mixin' annotation (which only prevents non-mixin use). "Normal" templates can be mixed in too, see my `Tmpl` example above. T foo(T)() { return bar; } auto f(int bar) { mixin foo!double blah; return blah.foo(); } void main() { assert (f(42)==42.0); }
Recursive mixin templates, which is mostly the reason I'm using this, won't work: string foo(string x)() { return x; } string foo(string x, T...)() { mixin foo!T _foo; return x ~ y ~ _foo.foo(); } // mixin foo!("a", "b"); // dies on foo not a template
 2. Eponymous trick, calling end
 
 mixin foo!T;
 
 to also include as syntactic support
 
 alias foo = foo!T.foo;
 
 as well as the named version you listed.
No, that would hide the `foo` template symbol. There's no such problem with the named version (other than the eponymous look-up not working).
I just mean the eponymous look-up part of it, whatever the compiler-generated alias looks like.
 3. Inline/anonymous mixins
 
 Some way of writing the equivalent of
 
 bar = (mixin foo!T)() + 3;
This part I'm not sure about. Can't think of an interesting use case, that wouldn't be better handled in some other way. The obvious workaround would be: bar = { mixin foo!T f; return f()+3; }(); // today: `f.foo()+3` [`{...}()` might result in a lambda/closure right now, but that should really be fixed (ie defined as a special case)] artur
Yeah, it's probably easier to do auto foo = { mixin foo!T f; return f.foo; }() and take one name. With the mixin using enclosing scope, can it be function and not delegate?
Jun 08 2015
next sibling parent "Jeffrey Tsang" <jeffrey.tsang ieee.org> writes:
On Monday, 8 June 2015 at 20:04:00 UTC, Jeffrey Tsang wrote:
 On Monday, 8 June 2015 at 16:27:36 UTC, Artur Skawina wrote:
 On 06/08/15 17:14, Jeffrey Tsang via Digitalmars-d wrote:
 On Sunday, 7 June 2015 at 14:17:45 UTC, Artur Skawina wrote:
 On 06/07/15 11:05, Jeffrey Tsang via Digitalmars-d wrote:
 I use a mixin template to define exactly one symbol, and at 
 instantiation I wish to use that symbol immediately, once.
AFAICT you're asking for the commented-out line in auto Tmpl() = l; void main(string[] argv) { auto l = argv.length; mixin Tmpl!() a; assert(a.Tmpl==l); //assert(a==l); } to work. That would probably be enough, make sense and have no serious backward compat issues.
There are three separate things I would like to have: 1. Eponymous trick mixin T foo(T)() { return bar; } as pure syntactic sugar for mixin template foo(T) { T foo() { return bar; } }
This part already works, if you leave out the 'mixin' annotation (which only prevents non-mixin use). "Normal" templates can be mixed in too, see my `Tmpl` example above. T foo(T)() { return bar; } auto f(int bar) { mixin foo!double blah; return blah.foo(); } void main() { assert (f(42)==42.0); }
Recursive mixin templates, which is mostly the reason I'm using this, won't work: string foo(string x)() { return x; } string foo(string x, T...)() { mixin foo!T _foo; return x ~ y ~ _foo.foo(); } // mixin foo!("a", "b"); // dies on foo not a template
 2. Eponymous trick, calling end
 
 mixin foo!T;
 
 to also include as syntactic support
 
 alias foo = foo!T.foo;
 
 as well as the named version you listed.
No, that would hide the `foo` template symbol. There's no such problem with the named version (other than the eponymous look-up not working).
I just mean the eponymous look-up part of it, whatever the compiler-generated alias looks like.
 3. Inline/anonymous mixins
 
 Some way of writing the equivalent of
 
 bar = (mixin foo!T)() + 3;
This part I'm not sure about. Can't think of an interesting use case, that wouldn't be better handled in some other way. The obvious workaround would be: bar = { mixin foo!T f; return f()+3; }(); // today: `f.foo()+3` [`{...}()` might result in a lambda/closure right now, but that should really be fixed (ie defined as a special case)] artur
Yeah, it's probably easier to do auto foo = { mixin foo!T f; return f.foo; }() and take one name. With the mixin using enclosing scope, can it be function and not delegate?
I meant auto foo = { mixin foo!T f; return &f.foo; }(); and then use the function normally.
Jun 08 2015
prev sibling parent Artur Skawina via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 06/08/15 22:03, Jeffrey Tsang via Digitalmars-d wrote:
 Recursive mixin templates, which is mostly the reason I'm using this, won't
work:
 
 string foo(string x)() {
     return x;
 }
 
 string foo(string x, T...)() {
     mixin foo!T _foo;
     return x ~ y ~ _foo.foo();
 }
 
 // mixin foo!("a", "b"); // dies on foo not a template
No, it's just another D "feature" that gets in the way - the name of a template resolves to the current instantiation when used inside the template. If your templates are in module scope the workaround is simple: string foo(string x, T...)() { mixin .foo!T _foo; return x ~ _foo.foo(); } It they are not, it gets more interesting.
 3. Inline/anonymous mixins

 Some way of writing the equivalent of

 bar = (mixin foo!T)() + 3;
This part I'm not sure about. Can't think of an interesting use case, that wouldn't be better handled in some other way. The obvious workaround would be: bar = { mixin foo!T f; return f()+3; }(); // today: `f.foo()+3` [`{...}()` might result in a lambda/closure right now, but that should really be fixed (ie defined as a special case)]
 Yeah, it's probably easier to do
 
 auto foo = { mixin foo!T f; return f.foo; }()
 
 and take one name. With the mixin using enclosing scope, can it be function
and not delegate?
No, but a delegate that's immediately executed could be placed inline and does not require a closure. Some way to use statements and declarations inside expressions is needed anyway, and this syntax would be natural in D (even C compilers have this as an extension, eg gcc's "statement expressions").
 I meant
     auto foo = { mixin foo!T f; return &f.foo; }();
 and then use the function normally.
That may work for function, which have effectively infinite lifetime, but is not a good idea for other objects. artur
Jun 09 2015