Hello there,
I was just working on an example for my upcoming library core.reflect
and I wanted to contrast it with the current template way of doing things.
The issue at hand here is getting all the names of top-level (free)function in a module in a string[].
The way that I found to do this with templates involves a bit of knowledge of is expressions here it is
template functionNames (alias M)
{
static const functionNames = ()
{
string[] names;
foreach(m;__traits(derivedMembers, M))
{
alias sym = __traits(getMember, M, m);
static if (is(typeof(sym) T) && is(T F == function))
{
names ~= __traits(identifier, sym);
}
}
return names;
} ();
}
Note that on the "callsite" you have to instantiate the helper template as:
static const fNames = functionNames!(mixin(__MODULE__))
;
the parens around the mixin are not optional it will not parse without them.
now comes the way do that with core.reflect.
@(core.reflect) // annotation prevents code-gen since the `nodeFromName` builtin which is called in there is not a real function and therefore has no body for the codegenerator to look at.
const(FunctionDeclaration)[] getFreeFunctionNamesFromModule(
string module_ = __MODULE__,
ReflectFlags flags = ReflectFlags.NoMemberRecursion,
immutable Scope _scope = currentScope()
)
{
string[] result;
auto mod_ = nodeFromName(module_, flags, _scope);
if (auto mod = cast(Module) mod_)
foreach(member;mod.members)
{
if (auto fd = cast(const FunctionDeclaration) member)
{
result ~= fd.name;
}
}
return result;
}
and you use it like this.
static const functionNames = getFreeFunctionNamesFromModule;
I am using a parenthesis less call to make it look like it's a magic builtin but in reality the only bits of magic that are used are the two builtins nodeFromName
and currentScope
whereas the template above used 5 magic constructs.
- 2 different types of pattern matching is expressions.
and - 3 different __traits expressions.