Comment #0 by andrej.mitrovich — 2013-08-14T15:33:58Z
Currently there doesn't seem to be a way to retrieve the address of a lambda function.
If for any reason you need to know the address of the lambda function /within/ the body of the lambda, you can't currently do this without assigning it to another variable.
The use-case are signals. Here's a contrived example:
-----
module test;
import std.stdio;
struct Signal
{
void connect(void delegate(int) func)
{
funcs ~= func;
}
void disconnect(void delegate(int) target)
{
foreach (idx, func; funcs)
{
if (func is target)
{
funcs = funcs[0 .. idx] ~ funcs[idx + 1 .. $];
break;
}
}
}
void emit(int i)
{
foreach (func; funcs)
func(i);
}
void delegate(int)[] funcs;
}
void main()
{
Signal signal;
void delegate(int) handler;
handler =
(int i)
{
stderr.writefln("handler called with %s", i);
if (i == 2)
{
signal.disconnect(handler); // ok
}
};
signal.connect(handler);
signal.emit(1);
signal.emit(2);
signal.emit(3);
}
-----
In 'main', the lambda function is assigned to a 'handler' variable. The lambda's body can then reference this variable if it needs to pass its address around. It uses this address to disconnect itself from a list of signal handlers.
Do note however that using this code is only possible because the lambda is a delegate and not a function type! IOW, calling "signal.disconnect(handler)" would not be possible if the lambda was a function. If it was a function it wouldn't have access to the outer frame to get the value of 'handler', even though it is de-facto an address of itself. Of course using the 'signal' variable also forces the lambda to be a delegate, but that's not important.
If we had a way to retrieve the address of a lambda from within the body of the lambda, we could both:
1) Avoid having to assign the lambda to a variable in order to retrieve the address from within the labmda body
2) In some cases avoid having to make the lambda a delegate due to #1
This would allow using code such as the following:
-----
import std.stdio;
// note1: changed to accept functions
// note2: now passing a signal reference explicitly
struct Signal
{
void connect(void function(ref Signal, int) func)
{
funcs ~= func;
}
void disconnect(void function(ref Signal, int) target)
{
foreach (idx, func; funcs)
{
if (func is target)
{
funcs = funcs[0 .. idx] ~ funcs[idx + 1 .. $];
break;
}
}
}
void emit(int i)
{
foreach (func; funcs)
func(this, i);
}
void function(ref Signal, int)[] funcs;
}
void main()
{
Signal signal;
// connect to anonymous function
signal.connect((ref Signal theSignal, int i)
{
stderr.writefln("handler called with %s", i);
if (i == 2)
{
// new trait: get the address of this lambda
theSignal.disconnect(__traits(addressOfThis));
}
});
signal.emit(1);
signal.emit(2);
signal.emit(3); // no longer calls the lambda
}
-----
I suppose __traits(addressOfThis) could also be useful in classes, to avoid having to use "cast(void*)this" or even the opCast-safe "*cast(void**)&this".
Comment #1 by andrej.mitrovich — 2013-08-14T15:38:16Z
(In reply to comment #0)
> theSignal.disconnect(__traits(addressOfThis));
I did just realize that addressOfThis would have to return a typed pointer (e.g. void delegate(...) or void function(...)) rather than a vanilla void*, so addressOfThis is likely a bad name. A better concept name might be a getThis trait, where the trait returns the typed reference.
Comment #2 by robert.schadek — 2024-12-13T18:10:19Z