Thread overview
Explicit cast to @system?
Oct 08, 2022
Anonymouse
Oct 09, 2022
tsbockman
Oct 09, 2022
Anonymouse
Oct 09, 2022
user1234
Oct 09, 2022
Anonymouse
October 08, 2022

I have some nested templated code that takes function pointers. In many cases I pass it functions of identical signatures, except some are @safe and others are @system. In those cases the templates end up getting instantiated twice. I don't care about the @safe-ness and I'd really like to just have them all treated as @system, with one instantiation per unique signature.

To illustrate:

void foo(F)(F fun)
{
    pragma(msg, F.stringof);
}

void bar() @safe {}
void baz() @system {}

void main()
{
    foo(&bar);
    foo(&baz);
}

Outputs:

void function() @safe
void function()

I can do this by explicitly passing the type as a template parameter;

void main()
{
    foo!(void function() @system)(&bar);
    foo(&baz);
}

...but there are a lot of different signatures and I need a general approach. There doesn't seem to be such a thing as cast(@system)fp.

My current solution involves some very gnarly string mixins.

static if (F.stringof.indexOf("@safe") != -1)
{
    mixin("alias SystemF = " ~ F.stringof.replace("@safe", "@system") ~ ";");
}
else
{
    alias SystemF = F;
}

...where F is void function(), @safe or @system. Then I can explicitly pass SystemF as a compile-time parameter, and I get my decreased instantiations.

But surely there has to be a better way?

October 09, 2022

On Saturday, 8 October 2022 at 23:06:13 UTC, Anonymouse wrote:

>

I have some nested templated code that takes function pointers. In many cases I pass it functions of identical signatures, except some are @safe and others are @system. In those cases the templates end up getting instantiated twice. I don't care about the @safe-ness and I'd really like to just have them all treated as @system, with one instantiation per unique signature.
...
But surely there has to be a better way?

You might be templating more information than necessary. In your example foo doesn't need to be a template at all:

void foo(void function() @system fun) {
    pragma(msg, typeof(fun).stringof);
}

If your real code needs to template the return type and parameters of fun, for example, consider just templating those instead of the whole function pointer type:

void foo(R, P...)(R function(P) @system fun) {
    pragma(msg, typeof(fun).stringof);
}

(Things do get awkward with ref and out, though, because D considers them to be part of the function's type rather than part of the parameter or return types. ref is the bane of my D meta-programming existence.)

October 09, 2022

On Saturday, 8 October 2022 at 23:06:13 UTC, Anonymouse wrote:

>

I have some nested templated code that takes function pointers. In many cases I pass it functions of identical signatures, except some are @safe and others are @system. In those cases the templates end up getting instantiated twice. I don't care about the @safe-ness and I'd really like to just have them all treated as @system, with one instantiation per unique signature.

To illustrate:

[...]

...but there are a lot of different signatures and I need a general approach. There doesn't seem to be such a thing as cast(@system)fp.

My current solution involves some very gnarly string mixins.

I see what you mean, in the past I wanted cast(pure), cast(nothrow), similarly to avoid using metaprog (or maybe was that delegates) in certain case.

>

[...]
But surely there has to be a better way?

No.

October 09, 2022

On Sunday, 9 October 2022 at 16:25:22 UTC, tsbockman wrote:

>

You might be templating more information than necessary. In your example foo doesn't need to be a template at all:

void foo(void function() @system fun) {
    pragma(msg, typeof(fun).stringof);
}

Yes, it was a toy example. It's complicated and I need crayons to explain it well, but the real code is a nested function in a main function in a template mixin, mixed into a class in a module dedicated to it. When invoked the main function introspects module-level functions annotated with particular UDAs and calls them -- or doesn't, depending on other factors. Several modules (grep says 23) then each have their own class types that mix in this mixin, and each module's module-level functions take that module's class as parameter. Like the hello world example does here.

So the __FUNCTION__ string of one instance of the nested function could be (and note the @safe):

kameloso.plugins.notes.NotesPlugin.IRCPluginImpl!(Flag.no, "kameloso.plugins.notes").onEventImpl.process!(false, false, void function(NotesPlugin, ref const(IRCEvent)) @safe).process

Even if I somehow manage to change the nested process to not be a template I still need to instantiate the housing IRCPluginImpl mixin once per class (and module), so I'm not sure. I could just annotate everything @system too.

October 09, 2022

On Sunday, 9 October 2022 at 17:42:57 UTC, user1234 wrote:

> >

But surely there has to be a better way?

No.

Darn. Okay, thanks.