digitalmars.D - Eponymous/anonymous mixin templates
- Jeffrey Tsang (39/39) Jun 07 2015 I've been doing some fun template metaprogramming recently for a
- Artur Skawina via Digitalmars-d (12/13) Jun 07 2015 AFAICT you're asking for the commented-out line in
- Jeffrey Tsang (22/36) Jun 08 2015 There are three separate things I would like to have:
- Artur Skawina via Digitalmars-d (27/74) Jun 08 2015 This part already works, if you leave out the 'mixin' annotation
- Jeffrey Tsang (17/92) Jun 08 2015 Recursive mixin templates, which is mostly the reason I'm using
- Jeffrey Tsang (4/107) Jun 08 2015 I meant
- Artur Skawina via Digitalmars-d (18/52) Jun 09 2015 No, it's just another D "feature" that gets in the way -
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
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
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: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;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 08 2015
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: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); }On 06/07/15 11:05, Jeffrey Tsang via Digitalmars-d wrote: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; } }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.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
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: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 templateOn Sunday, 7 June 2015 at 14:17:45 UTC, Artur Skawina wrote: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); }On 06/07/15 11:05, Jeffrey Tsang via Digitalmars-d wrote: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; } }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.I just mean the eponymous look-up part of it, whatever the compiler-generated alias looks like.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).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?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
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:I meant auto foo = { mixin foo!T f; return &f.foo; }(); and then use the function normally.On 06/08/15 17:14, 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 templateOn Sunday, 7 June 2015 at 14:17:45 UTC, Artur Skawina wrote: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); }On 06/07/15 11:05, Jeffrey Tsang via Digitalmars-d wrote: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; } }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.I just mean the eponymous look-up part of it, whatever the compiler-generated alias looks like.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).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?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
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 templateNo, 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









"Jeffrey Tsang" <jeffrey.tsang ieee.org> 