digitalmars.D.learn - Referring to alias parameters in a mixin template
- aldanor (27/27) Dec 16 2014 Would something like this be possible at all? A hypothetical
- aldanor (11/11) Dec 16 2014 A partial solution would be something like this:
- anonymous (9/16) Dec 16 2014 The polution isn't too bad. Mixed-in symbols are second class. A
- aldanor (6/11) Dec 16 2014 Thanks, that looks exactly like what I need -- I figured
- anonymous (6/8) Dec 16 2014 Sure, straight forward:
- aldanor (5/10) Dec 16 2014 Indeed... thanks! Just one thing that I find confusing here -- how
- ketmar via Digitalmars-d-learn (8/20) Dec 17 2014 On Wed, 17 Dec 2014 02:34:15 +0000
- anonymous (32/45) Dec 17 2014 As far as I understand, the string mixin is resolved first, and
Would something like this be possible at all? A hypothetical mixin template mixin template makeProperty(T, string name, alias func) { ... } that could be called like this: makeProperty!(int, "foo", f) and would generate code like int property foo() { return f(); } This is a very simplified example of what I'm trying to do, but I'm a bit stuck at this point -- if I'm generating the code as a string, how do I know how to refer to "func" alias (traits identifier / fullyQualifiedName just don't cut it for a lot of cases)? For one, thing, it could be an anonymous delegate like { return 0; } or symbol from another module or anything else. This is obviously doable if "func" is a string that gets mixed in, but what if it is an alias? Without the "name" part, one could sure use a simple template: template makeUnnamedProperty(T, alias func) { T makeUnnamedProperty() property { return func(); } } and then this works... alias foo = makeUnnamedProperty!(int, f); However, how does the one go about templating this when "foo" is a (compile-time) string? Wonder if I'm missing something... Thanks.
Dec 16 2014
A partial solution would be something like this: mixin template makeProperty(T, string name, alias func) { enum p = makeUnnamedProperty!(T, func); mixin("enum %s = p;".format(name)); // or alias } however now the parent namespace is polluted with "p", is there any way to hide it away and/or avoid it? I may be wrong, but I guess the whole thing boils down to a question whether it's possible to have a mixin template with signature 'bind(string name, alias symbol)' which generates 'enum foo = bar;' when called as 'mixin bind!("foo", bar)'?
Dec 16 2014
On Wednesday, 17 December 2014 at 01:14:36 UTC, aldanor wrote:A partial solution would be something like this: mixin template makeProperty(T, string name, alias func) { enum p = makeUnnamedProperty!(T, func); mixin("enum %s = p;".format(name)); // or alias } however now the parent namespace is polluted with "p", is there any way to hide it away and/or avoid it?The polution isn't too bad. Mixed-in symbols are second class. A symbol not from a mixin would win, and multiple mixed-in `p`s would only conflict on use. But if you want to avoid `p`, just do the substitution: mixin template makeProperty(T, string name, alias func) { mixin("enum %s = makeUnnamedProperty!(T, func);".format(name)); // or alias }
Dec 16 2014
On Wednesday, 17 December 2014 at 01:39:07 UTC, anonymous wrote:But if you want to avoid `p`, just do the substitution: mixin template makeProperty(T, string name, alias func) { mixin("enum %s = makeUnnamedProperty!(T, func);".format(name)); // or alias }Thanks, that looks exactly like what I need -- I figured something like this would compile, but I guess it's slightly counterintuitive that you can access "T" and 'func" this way. Wonder if this is doable within a single mixin template without using makeUnnamedProperty?
Dec 16 2014
On Wednesday, 17 December 2014 at 01:49:14 UTC, aldanor wrote:Wonder if this is doable within a single mixin template without using makeUnnamedProperty?Sure, straight forward: mixin template makeProperty(T, string name, alias func) { mixin("T %s() property { return func(); }".format(name)); }
Dec 16 2014
On Wednesday, 17 December 2014 at 02:12:52 UTC, anonymous wrote:Sure, straight forward: mixin template makeProperty(T, string name, alias func) { mixin("T %s() property { return func(); }".format(name)); }Indeed... thanks! Just one thing that I find confusing here -- how exactly do T and func resolve when this template is mixed in? What if there was another local symbol named "func" in the target scope?
Dec 16 2014
On Wed, 17 Dec 2014 02:34:15 +0000 aldanor via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> wrote:On Wednesday, 17 December 2014 at 02:12:52 UTC, anonymous wrote:this is mixed inside the `makeProperty` template itself, not where you instantiated it. i.e. when compiler sees mixin, it not postponing it. so what you actually got is `makeProperty` template with `%s` substituted with `name`, and only then `makeProperty` is mixed at the place of it's instatiation.Sure, straight forward: mixin template makeProperty(T, string name, alias func) { mixin("T %s() property { return func(); }".format(name)); }=20 Indeed... thanks! Just one thing that I find confusing here -- how exactly do T and func resolve when this template is mixed in? What if there was another local symbol named "func" in the target scope?
Dec 17 2014
On Wednesday, 17 December 2014 at 02:34:16 UTC, aldanor wrote:On Wednesday, 17 December 2014 at 02:12:52 UTC, anonymous wrote:As far as I understand, the string mixin is resolved first, and then the template mixin takes place. So the progression is somewhat like this (pseudo code): ---- mixin makeProperty!(int, "foo", f); /* Replace "makeProperty" with its definition. */ mixin (T, name, func){mixin("T %s() property { return func();}".format(name));}!(int, "foo", f); /* First round, substitute arguments for parameters. `T` and `func` are not replaced, because they're just string contents at this point. */ mixin (T, name, func){mixin("T %s() property { return func();}".format("foo"));}!(int, "foo", f); /* Evaluate `format` and do the string mixin. */ mixin (T, name, func){T foo() property { return func();}}!(int, "foo", f); /* Second round, substitute arguments for parameters. This time, `T` and `func` are replaced. */ mixin (T, name, func){int foo() property { return f();}}!(int, "foo", f); /* Didn't do any string mixins in the second round, so there's no need for a third round. Get rid of template parameters and arguments. */ mixin {int foo() property { return f();}}; /* Finally, do the template mixin. */ int foo() property { return f();} ---- Not sure if that helps or maybe it just adds to the confusion. As to if there were `T` or `func` in the target scope, they'd be shadowed by the template parameters, no matter if there's a string mixin or not.Sure, straight forward: mixin template makeProperty(T, string name, alias func) { mixin("T %s() property { return func(); }".format(name)); }Indeed... thanks! Just one thing that I find confusing here -- how exactly do T and func resolve when this template is mixed in? What if there was another local symbol named "func" in the target scope?
Dec 17 2014
On Wednesday, 17 December 2014 at 12:49:10 UTC, anonymous wrote:As far as I understand, the string mixin is resolved first, and then the template mixin takes place. So the progression is somewhat like this (pseudo code): ---- mixin makeProperty!(int, "foo", f); /* Replace "makeProperty" with its definition. */ mixin (T, name, func){mixin("T %s() property { return func();}".format(name));}!(int, "foo", f); /* First round, substitute arguments for parameters. `T` and `func` are not replaced, because they're just string contents at this point. */ mixin (T, name, func){mixin("T %s() property { return func();}".format("foo"));}!(int, "foo", f); /* Evaluate `format` and do the string mixin. */ mixin (T, name, func){T foo() property { return func();}}!(int, "foo", f); /* Second round, substitute arguments for parameters. This time, `T` and `func` are replaced. */ mixin (T, name, func){int foo() property { return f();}}!(int, "foo", f); /* Didn't do any string mixins in the second round, so there's no need for a third round. Get rid of template parameters and arguments. */ mixin {int foo() property { return f();}}; /* Finally, do the template mixin. */ int foo() property { return f();} ---- Not sure if that helps or maybe it just adds to the confusion. As to if there were `T` or `func` in the target scope, they'd be shadowed by the template parameters, no matter if there's a string mixin or not.That makes sense. So if I understand correctly, basically after each string mixin it has to check if any new symbols were leaked into the current scope and then try to resolve them, if any, with template parameters taking precedence over local variables? (This obviously has to repeat in case of nested mixins) Thanks again!
Dec 17 2014
On Wednesday, 17 December 2014 at 15:40:25 UTC, aldanor wrote:On Wednesday, 17 December 2014 at 12:49:10 UTC, anonymous wrote:[...]Well, every mixed-in string necessarily goes through a full compiler pass. I don't think there's anything special going on with regards to new symbols.As to if there were `T` or `func` in the target scope, they'd be shadowed by the template parameters, no matter if there's a string mixin or not.That makes sense. So if I understand correctly, basically after each string mixin it has to check if any new symbols were leaked into the current scope and then try to resolve them, if any,with template parameters taking precedence over local variables? (This obviously has to repeat in case of nested mixins)My wording was bad. There's no shadowing. When a template is mixed in, the substitution of parameters happens before the injection. That means, when the parameters are substituted there are no local symbols yet. And when the code is injected there are no parameters any more. So local symbols and parameters are never considered at the same time. Obviously, parameters take precedence, simply because they're considered earlier. But there's no shadowing. Disclaimer: I'm not a compiler dev. I don't know if/how all this is specified (or I'd quote/link it). I'm just describing current compiler behaviour and how it makes sense to me.
Dec 17 2014