Thread overview
Resolve function pointers using UDA during CT
Feb 09, 2014
Tim Volckmann
Feb 09, 2014
Jakob Ovrum
Feb 09, 2014
Tim Volckmann
Feb 09, 2014
Jakob Ovrum
Feb 09, 2014
Philippe Sigaud
Feb 09, 2014
Jakob Ovrum
Feb 23, 2014
Tim Volckmann
Feb 09, 2014
Philippe Sigaud
February 09, 2014
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?
February 09, 2014
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.
February 09, 2014
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?
February 09, 2014
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)();
}
---
February 09, 2014
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)
February 09, 2014
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`.
February 09, 2014
On Sunday, 9 February 2014 at 13:48:36 UTC, Philippe Sigaud wrote:
> callbacks[attribute.Name] = mixin("&" ~ symbol);

callbacks[attribute.Name] = &mixin(symbol);
February 23, 2014
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!