Discussion:
Resolve function pointers using UDA during CT
(too old to reply)
Tim Volckmann
2014-02-09 12:48:35 UTC
Permalink
Hi guys,

is there any way to create an function-array during CT using UDAs
like the following:

module myUdaFunctions;

struct MyUDA
{
string Name;
}

@MyUDA("Function1")
string myFirstUdaFunction(string myString)
{
// ... do something
}

@MyUDA("Function2")
string mySecondUdaFunction(string myString)
{
// ... do something
}

/////////////////////

module myMain;

private
{
string function(string)[string] callbacks;
}

void main(string[] args)
{
// during ct:
{
// do something like this:
//
// auto u = __traits(getFunctionsByAttribute, "MyUDA")
// foreach (myFunction; u)
// callbacks[myFunction.GetAttribute("MyUDA").Name] =
myFunction
}

// during runtime:
if (args[1] in callbacks)
{
callbacks[args[1]]("myString");
}

}

Any way to do something like this?
Jakob Ovrum
2014-02-09 13:03:46 UTC
Permalink
Post by Tim Volckmann
Any way to do something like this?
No, associative arrays cannot be transferred from compile-time to
runtime yet, due to implementation issues. The next best thing
you can do is to use a module constructor with a generated body
that fills the AA.
Tim Volckmann
2014-02-09 13:10:13 UTC
Permalink
Post by Jakob Ovrum
Post by Tim Volckmann
Any way to do something like this?
No, associative arrays cannot be transferred from compile-time
to runtime yet, due to implementation issues. The next best
thing you can do is to use a module constructor with a
generated body that fills the AA.
You mean using static this as follows?:

module myMain;

private
{
string function(string)[string] callbacks;
}

static this()
{
{
// do something like this:
//
// auto u = __traits(getFunctionsByAttribute, "MyUDA")
// foreach (myFunction; u)
// callbacks[myFunction.GetAttribute("MyUDA").Name] =
myFunction
}
}

void main(string[] args)
{

if (args[1] in callbacks)
{
callbacks[args[1]]("myString");
}

}

That's also possible... but how can I find all functions with
MyUDA?
Jakob Ovrum
2014-02-09 13:16:09 UTC
Permalink
Post by Tim Volckmann
That's also possible... but how can I find all functions with
MyUDA?
There is no global list of symbols with a given UDA, you have to
search using __traits(allMembers) and such. the allMembers trait
can be used on modules.

If the functions with the UDAs are in user-defined modules, you
need to have the user specify those modules (so a module
constructor is not an option):

---
import mylib;
import usermod1, usermod2;

void main()
{
registerFunctions!(usermod1, usermod2)();
}
---
Philippe Sigaud
2014-02-09 13:48:13 UTC
Permalink
That's also possible... but how can I find all functions with MyUDA?
Here is a possibility:

***********
module myUDAFunctions;

import std.stdio;

struct MyUDA
{
string Name;
}

@MyUDA("Function1")
string myFirstUdaFunction(string myString)
{
writeln("MyFirstUDAFunction called with ", myString);
return "first";
}

@MyUDA("Function2")
string mySecondUdaFunction(string myString)
{
writeln("MySecondUDAFunction called with ", myString);
return "second";
}
**************
module myMain;

import std.stdio;
import std.traits;
import std.typetuple;

import myUDAFunctions;

private
{
string function(string)[string] callbacks;
}

static this()
{
// Getting all symbols from module myUDAFunctions
// Beware: we get strings, not aliases.
// Hence the mixin() afterwards to inject them in our code
foreach(symbol; __traits(allMembers, myUDAFunctions))
static if (isCallable!(mixin(symbol))) // Found some callable
{
// Extracting attributes
foreach(attribute; __traits(getAttributes, mixin(symbol)))
{
// Finding those which are MyUDA's
static if (is(typeof(attribute) == MyUDA))
callbacks[attribute.Name] = mixin("&" ~ symbol);
}
}
}

void main(string[] args)
{
writeln("Callbacks: ", callbacks);
writeln("Args: ", args);
if (args[1] in callbacks)
{
writeln(args[1], " known in callbacks");
callbacks[args[1]]("myString");
}
}
************

it's a be cumbersome, you should extract the pattern and put it in a
template with MyUDA and the module name as parameters.

Note the ` callbacks[attribute.Name] = mixin("&" ~ symbol);` line:

since `symbol` is a string, we have to mix it in the code.
And since `functionName` is seen as a call to `functionName` and not
as the function itself, I had to put an `&` before it
(the generated code is `callbakcs["Func1"] = &Fun1;`, for example)
Philippe Sigaud
2014-02-09 13:49:19 UTC
Permalink
On Sun, Feb 9, 2014 at 2:48 PM, Philippe Sigaud
Post by Philippe Sigaud
import std.stdio;
import std.traits;
import std.typetuple;
Hmm, std.typetuple is not necessary. And std.traits is used only to
import `isCallable`.
Jakob Ovrum
2014-02-09 13:59:18 UTC
Permalink
Post by Philippe Sigaud
callbacks[attribute.Name] = mixin("&" ~ symbol);
callbacks[attribute.Name] = &mixin(symbol);
Tim Volckmann
2014-02-23 09:40:45 UTC
Permalink
On Sun, Feb 9, 2014 at 2:10 PM, Tim Volckmann
Post by Tim Volckmann
That's also possible... but how can I find all functions with
MyUDA?
***********
module myUDAFunctions;
import std.stdio;
struct MyUDA
{
string Name;
}
@MyUDA("Function1")
string myFirstUdaFunction(string myString)
{
writeln("MyFirstUDAFunction called with ", myString);
return "first";
}
@MyUDA("Function2")
string mySecondUdaFunction(string myString)
{
writeln("MySecondUDAFunction called with ", myString);
return "second";
}
**************
module myMain;
import std.stdio;
import std.traits;
import std.typetuple;
import myUDAFunctions;
private
{
string function(string)[string] callbacks;
}
static this()
{
// Getting all symbols from module myUDAFunctions
// Beware: we get strings, not aliases.
// Hence the mixin() afterwards to inject them in our code
foreach(symbol; __traits(allMembers, myUDAFunctions))
static if (isCallable!(mixin(symbol))) // Found some
callable
{
// Extracting attributes
foreach(attribute; __traits(getAttributes,
mixin(symbol)))
{
// Finding those which are MyUDA's
static if (is(typeof(attribute) == MyUDA))
callbacks[attribute.Name] = mixin("&" ~
symbol);
}
}
}
void main(string[] args)
{
writeln("Callbacks: ", callbacks);
writeln("Args: ", args);
if (args[1] in callbacks)
{
writeln(args[1], " known in callbacks");
callbacks[args[1]]("myString");
}
}
************
it's a be cumbersome, you should extract the pattern and put it
in a
template with MyUDA and the module name as parameters.
Note the ` callbacks[attribute.Name] = mixin("&" ~ symbol);`
since `symbol` is a string, we have to mix it in the code.
And since `functionName` is seen as a call to `functionName`
and not
as the function itself, I had to put an `&` before it
(the generated code is `callbakcs["Func1"] = &Fun1;`, for
example)
Works as expected, thanks Jakob and Philippe!

Loading...