www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Resolve function pointers using UDA during CT

reply "Tim Volckmann" <timvol ymail.com> writes:
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?
Feb 09 2014
parent reply "Jakob Ovrum" <jakobovrum gmail.com> writes:
On Sunday, 9 February 2014 at 12:48:36 UTC, Tim Volckmann wrote:
 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.
Feb 09 2014
parent reply "Tim Volckmann" <timvol ymail.com> writes:
On Sunday, 9 February 2014 at 13:03:47 UTC, Jakob Ovrum wrote:
 On Sunday, 9 February 2014 at 12:48:36 UTC, Tim Volckmann wrote:
 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?
Feb 09 2014
next sibling parent "Jakob Ovrum" <jakobovrum gmail.com> writes:
On Sunday, 9 February 2014 at 13:10:14 UTC, Tim Volckmann wrote:
 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)(); } ---
Feb 09 2014
prev sibling next sibling parent reply Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Sun, Feb 9, 2014 at 2:10 PM, Tim Volckmann <timvol ymail.com> wrote:

 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)
Feb 09 2014
next sibling parent "Jakob Ovrum" <jakobovrum gmail.com> writes:
On Sunday, 9 February 2014 at 13:48:36 UTC, Philippe Sigaud wrote:
 callbacks[attribute.Name] = mixin("&" ~ symbol);
callbacks[attribute.Name] = &mixin(symbol);
Feb 09 2014
prev sibling parent "Tim Volckmann" <timvol ymail.com> writes:
On Sunday, 9 February 2014 at 13:48:36 UTC, Philippe Sigaud wrote:
 On Sun, Feb 9, 2014 at 2:10 PM, Tim Volckmann 
 <timvol ymail.com> wrote:

 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)
Works as expected, thanks Jakob and Philippe!
Feb 23 2014
prev sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Sun, Feb 9, 2014 at 2:48 PM, Philippe Sigaud
<philippe.sigaud gmail.com> wrote:
 import std.stdio;
 import std.traits;
 import std.typetuple;
Hmm, std.typetuple is not necessary. And std.traits is used only to import `isCallable`.
Feb 09 2014