www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Address of a lambda

reply FoxyBrown <Foxy Brown.IPT> writes:
In gtk, we routinly have to use delegates for callbacks. But the 
methods that accept these delegates want the address of the 
delegate, this prevents us from being able to pass a lambda in 
directly, but there really is not reason why we shouldn't be able 
to do this?

Fine:
void main()
{
bool windowDelete(Event event, Widget widget) {	Main.quit(); 
return false; }
MainWindow.addOnDelete(&windowDelete);
}

Invalid:

void main()
{
MainWindow.addOnDelete(&((Event event, Widget widget) 
{	Main.quit(); return false; }));
}


and yet, the only difference is a copy and paste(i.e., a rewrite 
rule, at most). Surely the compiler can figure out that we can 
take such an address because anything that actually exists must 
have an address somewhere. Seems like an arbitrary blocker? Even 
if it saves us from some obscure problems, it should work in most 
cases and be allowed when used in those cases.

What's even stranger is that the function windowDelete must be 
declared in some type of object, such as another function, so it 
is actually a delegate, if one has it in the module root then it 
is a normal function and cannot be passed to addOnDelete, even 
though, again, there is very little difference.

Invalid:

bool windowDelete(Event event, Widget widget) {	Main.quit(); 
return false; }

void main()
{
MainWindow.addOnDelete(&windowDelete);
}



I do know the difference between a delegate and a function, and I 
suppose addOnDelete should be defined to take a function instead? 
But how can we create a "delegate function" similar to the nested 
delegate in the first case that works so that we can pass them as 
delegates?

And aside, shouldn't all functions really be delegates? Having a 
closure of the outer scope still holds at the module root 
level(the scope is the module root). While it's an extra argument 
to pass, it could simplify live a bit. The corner cases could be 
handled by explicitly forcing it to be a function.
Jul 07
next sibling parent NoIdeaForaGoodPseudo <abaerrterreuuop oldbean.org> writes:
On Friday, 7 July 2017 at 17:33:33 UTC, FoxyBrown wrote:
 In gtk, we routinly have to use delegates for callbacks. But 
 the methods that accept these delegates want the address of the 
 delegate, this prevents us from being able to pass a lambda in 
 directly, but there really is not reason why we shouldn't be 
 able to do this?

 [...]
Lambdas are for very localized and small delegates, typically in algorithms and functional programming. Delegates assigned to events in GUI toolkits are often meant to be reusable, e.g assignable to different listeners and also must be known (have addresses) to be usable in GUI designers. That's not what lambda are made for.
Jul 07
prev sibling next sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 07/07/2017 10:33 AM, FoxyBrown wrote:
 In gtk, we routinly have to use delegates for callbacks. But the methods
 that accept these delegates want the address of the delegate,
I'm not a user but I don't think it's right. According to the following, it takes a delegate: https://github.com/gtkd-developers/GtkD/blob/42ef854f7cd975519926900fe326e220410c028a/demos/gtkD/DemoMultiCellRenderer/DemoMultiCellRenderer.d#L124 wnd.addOnDelete( delegate bool (Event event, Widget widget) { widget.destroy(); Main.quit(); return false; });
 this
 prevents us from being able to pass a lambda in directly, but there
 really is not reason why we shouldn't be able to do this?
I think that's because the lambda is a 'function' if can be for efficiency reasons.
 Invalid:

 void main()
 {
 MainWindow.addOnDelete(&((Event event, Widget widget) {    Main.quit();
 return false; }));
 }
It makes it very difficult to help if there is no code that demonstrates the problem. Here is my attempt and a solution with the addition of the keyword 'delegate': alias Event = int; alias Widget = int; struct MainWindow { static void quit() { } static void addOnDelete(bool delegate(Event, Widget)) { } } MainWindow Main; void main() { // ADDED 'delegate': MainWindow.addOnDelete(delegate (Event event, Widget widget) { Main.quit(); return false; }); } So, there is no need to take the address of a lambda. It's already either a 'function' or a delegate.
 I
 suppose addOnDelete should be defined to take a function instead?
That would limit the users if they wanted to maintain state for the function.
 But
 how can we create a "delegate function" similar to the nested delegate
 in the first case that works so that we can pass them as delegates?
Being explicit like above is one way. There is also toDelegate: https://dlang.org/phobos/std_functional.html#toDelegate
 And aside, shouldn't all functions really be delegates?
Not in a system language like D that tries to avoid unnecessary cost. :) Ali
Jul 07
next sibling parent FoxyBrown <Foxy Brown.IPT> writes:
On Friday, 7 July 2017 at 17:52:25 UTC, Ali Çehreli wrote:
 On 07/07/2017 10:33 AM, FoxyBrown wrote:
 [...]
the methods
 [...]
I'm not a user but I don't think it's right. According to the following, it takes a delegate: [...]
Thanks, I guess one doesn't need to pass the address(I copied the code from somewhere and it was so I made an assumption). One doesn't need the delegate keyword or &, but the question then is why does & work? Seems to have done not affect the behavior.
Jul 07
prev sibling parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 07/07/2017 10:52 AM, Ali Çehreli wrote:
 a solution with the addition of the
 keyword 'delegate':
As ag0aep6g explained, the 'delegate' keyword was not necessary there. A case where it's needed is when defining a variable. The following code compiles if 'delegate' keyword is present: void foo(int delegate (int)) { } void main() { // 'delegate' keyword needed to compile: auto f = delegate (int i) => i * 2; foo(f); } Ali
Jul 07
prev sibling parent ag0aep6g <anonymous example.com> writes:
On 07/07/2017 07:33 PM, FoxyBrown wrote:
 In gtk, we routinly have to use delegates for callbacks. But the methods 
 that accept these delegates want the address of the delegate,
I don't think that's true. As far as I can tell, this is the signature of addOnDelete [1]: ---- gulong addOnDelete(bool delegate(Event, Widget) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) ---- `dlg` is just a delegate, not a pointer to a delegate.
 this 
 prevents us from being able to pass a lambda in directly, but there 
 really is not reason why we shouldn't be able to do this?
 
 Fine:
 void main()
 {
 bool windowDelete(Event event, Widget widget) {    Main.quit(); return 
 false; }
 MainWindow.addOnDelete(&windowDelete);
 }
Here you're "taking the address" of a method. The result is a delegate, not a pointer to a delegate. The delegate is the address/pointer (plus another pointer to some related context).
 Invalid:
 
 void main()
 {
 MainWindow.addOnDelete(&((Event event, Widget widget) {    Main.quit(); 
 return false; }));
 }
Remove the `&` operator and it should work. The function literal [2] already makes a delegate.
 and yet, the only difference is a copy and paste(i.e., a rewrite rule, 
 at most). Surely the compiler can figure out that we can take such an 
 address because anything that actually exists must have an address 
 somewhere.
Stuff can exist in registers only. In a function call `f(42)`, 42 likely goes directly into a register, not into memory.
 Seems like an arbitrary blocker? Even if it saves us from 
 some obscure problems, it should work in most cases and be allowed when 
 used in those cases.
 
 What's even stranger is that the function windowDelete must be declared 
 in some type of object, such as another function, so it is actually a 
 delegate, if one has it in the module root then it is a normal function 
 and cannot be passed to addOnDelete, even though, again, there is very 
 little difference.
Yeah, that's an interesting oddity. The problem is that the parameters of a `void delegate(int foo, int bar)` are possibly passed differently from those of a `void function(int foo, int bar)`. Related thread: http://forum.dlang.org/post/ofc0lj$2u4h$1 digitalmars.com [...]
 I do know the difference between a delegate and a function, and I 
 suppose addOnDelete should be defined to take a function instead?
If anything, it should accept both. Not a function instead of a delegate.
 But 
 how can we create a "delegate function" similar to the nested delegate 
 in the first case that works so that we can pass them as delegates?
http://dlang.org/phobos/std_functional.html#toDelegate [1] https://github.com/gtkd-developers/GtkD/blob/5c2ee83aae7425b683709593c5fd44a7ab1db067/generated/gtkd/gtk/Widget.d#L6793 [2] https://dlang.org/spec/expression.html#function_literals
Jul 07