Thread overview | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
February 26, 2013 Passing a module in a template parameter list to __traits(allMembers, module) | ||||
---|---|---|---|---|
| ||||
Hi folks, In preparation for my upcoming talk at DConf 2013, I'm working on a compile-time dependency injection prototype for D. I'd like part of public interface for this system to take a module at compile time, and return a list of the classes in that module. Something like: string GetMembers(T)() { auto members = [__traits(allMembers, T)]; return join(result, ", "); } If I pass a module to __traits(allMembers, foo.bar) outside a template parameter list, it works great, but as soon as I pass it through a template parameter list, I get an odd error: Error: template instance GetMembers!(std) GetMembers!(std) does not match template declaration GetMembers(T)() Here's the code I'm working on. Any thoughts on whether this is possible, and if so, what I'm doing wrong? http://pastebin.com/BgZ67h8P Thanks, Ben |
February 26, 2013 Re: Passing a module in a template parameter list to __traits(allMembers, module) | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ben Gertzfield | On Tuesday, 26 February 2013 at 19:03:01 UTC, Ben Gertzfield wrote:
> Hi folks,
>
> In preparation for my upcoming talk at DConf 2013, I'm working on a compile-time dependency injection prototype for D.
>
> I'd like part of public interface for this system to take a module at compile time, and return a list of the classes in that module. Something like:
>
> string GetMembers(T)() {
> auto members = [__traits(allMembers, T)];
> return join(result, ", ");
> }
Use an alias:
string GetMembers(alias T)() {
auto members = [__traits(allMembers, T)];
return join(members, ", ");
}
void main() {
stdout.writefln("Got members: %s", GetMembers!(std.stdio));
}
Also make sure you parenthesize the call in GetMembers. For some reason these two are different:
GetMembers!std.stdio // actually calls (GetMembers!std).stdio
GetMembers!(std.stdio)
That could be a bug though.
|
February 26, 2013 Re: Passing a module in a template parameter list to __traits(allMembers, module) | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ben Gertzfield | On 02/26/2013 11:03 AM, Ben Gertzfield wrote:
> Hi folks,
>
> In preparation for my upcoming talk at DConf 2013, I'm working on a
> compile-time dependency injection prototype for D.
>
> I'd like part of public interface for this system to take a module at
> compile time, and return a list of the classes in that module. Something
> like:
>
> string GetMembers(T)() {
> auto members = [__traits(allMembers, T)];
> return join(result, ", ");
> }
>
> If I pass a module to __traits(allMembers, foo.bar) outside a template
> parameter list, it works great, but as soon as I pass it through a
> template parameter list, I get an odd error:
>
> Error: template instance GetMembers!(std) GetMembers!(std) does not
> match template declaration GetMembers(T)()
>
> Here's the code I'm working on. Any thoughts on whether this is
> possible, and if so, what I'm doing wrong?
>
> http://pastebin.com/BgZ67h8P
>
> Thanks,
>
> Ben
Hi Ben, I am in the same boat and I am about to post questions here about code problems. :)
Your first code works with three modifications:
1) std.stdio is not a type, so the template parameter list cannot be (T). I used 'alias'.
2) For syntax reasons, you must parenthesize (std.stdio) when passing as a template parameter
3) (You couldn't get to this yet.) A typo: result -> members
import std.array;
import std.stdio;
import std.traits;
string GetMembers(alias T)() {
auto members = [__traits(allMembers, T)];
return join(members, ", ");
}
void main() {
stdout.writefln("Got members: %s", GetMembers!(std.stdio));
}
Ali
|
February 26, 2013 Re: Passing a module in a template parameter list to __traits(allMembers, module) | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrej Mitrovic | On Tue, Feb 26, 2013 at 08:07:42PM +0100, Andrej Mitrovic wrote: [...] > Also make sure you parenthesize the call in GetMembers. For some reason these two are different: > > GetMembers!std.stdio // actually calls (GetMembers!std).stdio > GetMembers!(std.stdio) > > That could be a bug though. I think it's a problem with the precedence of the binary ! operator. It has higher precedence than '.', so GetMembers!std.stdio gets parsed as (GetMembers!std).stdio. Anyway, I've learned that if the argument after '!' is more than a single token, you should just parenthesize the whole thing, to be on the safe side. T -- BREAKFAST.COM halted...Cereal Port Not Responding. -- YHL |
February 26, 2013 Re: Passing a module in a template parameter list to __traits(allMembers, module) | ||||
---|---|---|---|---|
| ||||
On 2/26/13, H. S. Teoh <hsteoh@quickfur.ath.cx> wrote:
> I think it's a problem with the precedence of the binary ! operator.
Well it's definitely an edge-case we'll have to be careful about. :)
I don't know why packages can be passed as an alias. Do we have any defined behavior for using packages and traits?
|
February 26, 2013 Re: Passing a module in a template parameter list to __traits(allMembers, module) | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrej Mitrovic | On 2013-02-26 20:29, Andrej Mitrovic wrote: > Well it's definitely an edge-case we'll have to be careful about. :) > > I don't know why packages can be passed as an alias. Do we have any > defined behavior for using packages and traits? What the original post is doing, getting all its members? -- /Jacob Carlborg |
February 26, 2013 Re: Passing a module in a template parameter list to __traits(allMembers, module) | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrej Mitrovic | On Tuesday, 26 February 2013 at 19:07:43 UTC, Andrej Mitrovic wrote:
> Use an alias:
>
> string GetMembers(alias T)() {
Excellent. An alias parameter is just what I was looking for. Thanks, everyone!
Ben
|
February 27, 2013 Re: Passing a module in a template parameter list to __traits(allMembers, module) | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ben Gertzfield | > >> Use an alias: >> >> string GetMembers(alias T)() { > > > Excellent. An alias parameter is just what I was looking for. Thanks, everyone! Ben, I present some ideas on this problem in a template tutorial you can find here: https://github.com/PhilippeSigaud/D-templates-tutorial In the pdf, it's section 4.3.4 and 4.3.7, in the markdown file, the related sections are https://github.com/PhilippeSigaud/D-templates-tutorial/blob/master/D-templates-tutorial.md#allmembers and https://github.com/PhilippeSigaud/D-templates-tutorial/blob/master/D-templates-tutorial.md#getting-all-members-even-overloaded-ones And to answer H.S. Teoh's question, from the text: "What’s the point of inspecting a module? Well, first that was just for fun and to see if I could duplicate a module or create a struct with an equivalent members list (all forwarding to the module’s own members). But the real deal for me was when using string mixins to generate some type. If the user uses the mixin in its own module, it could create conflicts with already-existing names. So I searched for a way for a mixin template to inspect the module it’s currently being instantiated in. Then, I wanted to write a template that, given a class name, would give me the entire hierarchy it’s in (as the local module scope would see it, that was enough for me). Then, while testing std.traits.ParameterTypeTuple, I saw that it gives the parameter typetuple of one function, even when it’s overloaded. So inspecting a module is also a way to get the full list of functions with a particular name and getting the parameter typetuple for each of them." |
Copyright © 1999-2021 by the D Language Foundation