Bug 10822 – Need a way to get the address of a lambda function from within its body

Status
NEW
Severity
enhancement
Priority
P4
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2013-08-14T15:33:58Z
Last change time
2024-12-13T18:10:19Z
Assigned to
No Owner
Creator
Andrej Mitrovic
Moved to GitHub: dmd#18647 →

Comments

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
THIS ISSUE HAS BEEN MOVED TO GITHUB https://github.com/dlang/dmd/issues/18647 DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB