[Issue 10822] New: Need a way to get the address of a lambda function from within its body
d-bugmail at puremagic.com
d-bugmail at puremagic.com
Wed Aug 14 15:34:00 PDT 2013
http://d.puremagic.com/issues/show_bug.cgi?id=10822
Summary: Need a way to get the address of a lambda function
from within its body
Product: D
Version: D2
Platform: All
OS/Version: All
Status: NEW
Severity: enhancement
Priority: P2
Component: DMD
AssignedTo: nobody at puremagic.com
ReportedBy: andrej.mitrovich at gmail.com
--- Comment #0 from Andrej Mitrovic <andrej.mitrovich at gmail.com> 2013-08-14 15:33:58 PDT ---
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".
--
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
More information about the Digitalmars-d-bugs
mailing list