www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How to partially apply member functions?

reply ct <testing.in.chrome gmail.com> writes:
I have something similar to the following:

class Editor {
   void OnNextPreviousMatch(bool is_forward, SearchEntry entry) {
}
}
Jun 29 2017
parent reply ct <testing.in.chrome gmail.com> writes:
On Thursday, 29 June 2017 at 12:31:58 UTC, ct wrote:
 I have something similar to the following:

 class Editor {
   void OnNextPreviousMatch(bool is_forward, SearchEntry entry) {
 }
 }
I pressed send by mistake. Again, I have something similar to the following: class Editor { void OnNextPreviousMatch(bool is_forward, SearchEntry entry) { // ... } } In another member function, I want to partially apply a delegate: class Editor { void OnNextPreviousMatch(bool is_forward, SearchEntry entry) { // ... } void InstallHandlers() { entry_.addOnNextMatch(partial!(&this.OnNextPreviousMatch, true)); entry_.addOnPreviousMatch(partial!(&this.OnNextPreviousMatch, false)); } } I tried several things, but I keep getting compiler errors: Error: value of 'this' is not known at compile time /usr/include/dmd/phobos/std/functional.d(664,23): Error: need 'this' for 'OnNextPreviousMatch' of type 'void(bool is_forward, SearchEntry entry)'
Jun 29 2017
parent reply ct <testing.in.chrome gmail.com> writes:
I was only able to do it this way:

     auto on_next_previous = &this.OnNextPreviousMatch;
     entry_.addOnNextMatch(&partial!(on_next_previous, true));
     entry_.addOnPreviousMatch(&partial!(on_next_previous, false));
Jun 29 2017
parent reply Andrea Fontana <nospam example.com> writes:
On Thursday, 29 June 2017 at 13:01:10 UTC, ct wrote:
 I was only able to do it this way:

     auto on_next_previous = &this.OnNextPreviousMatch;
     entry_.addOnNextMatch(&partial!(on_next_previous, true));
     entry_.addOnPreviousMatch(&partial!(on_next_previous, 
 false));
I think you should provide a better example in order to get some help. We neither know what argument .addOnNextMatch() expects. Usually a full example on https://dpaste.dzfl.pl or other websites is more useful :) Andrea
Jun 29 2017
parent reply ct <testing.in.chrome gmail.com> writes:
On Thursday, 29 June 2017 at 14:30:19 UTC, Andrea Fontana wrote:
 On Thursday, 29 June 2017 at 13:01:10 UTC, ct wrote:
 I was only able to do it this way:

     auto on_next_previous = &this.OnNextPreviousMatch;
     entry_.addOnNextMatch(&partial!(on_next_previous, true));
     entry_.addOnPreviousMatch(&partial!(on_next_previous, 
 false));
I think you should provide a better example in order to get some help. We neither know what argument .addOnNextMatch() expects. Usually a full example on https://dpaste.dzfl.pl or other websites is more useful :) Andrea
Sorry. Please check this DPaste: https://dpaste.dzfl.pl/6379944510b8 addOnNextMatch() is gtk.SearchEntry.addOnNextMatch() [https://api.gtkd.org/gtkd/gtk/SearchEntry.html] which has the signature: gulong addOnNextMatch (void delegate(SearchEntry) dlg, ConnectFlags connectFlags = cast(ConnectFlags)0); So basically, it needs a void delegate(SearchEntry) as an argument. I wanted to create a single callback member function to handle both addOnNextMatch() and addOnPreviousMatch() by binding a bool value (true for next_match, false for previous_match) so that the callback knows which case it is handling. It compiled when I wrote: auto on_next_previous = &this.OnNextPreviousMatch; entry_.addOnNextMatch(&partial!(on_next_previous, true)); entry_.addOnPreviousMatch(&partial!(on_next_previous, false)); But not when I wrote: entry_.addOnNextMatch(partial!(&this.OnNextPreviousMatch, true)); Or entry_.addOnNextMatch(partial!(&Editor.OnNextPreviousMatch, true)); Error: value of 'this' is not known at compile time
Jun 30 2017
next sibling parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 06/30/2017 01:43 AM, ct wrote:

 entry_.addOnNextMatch(partial!(&this.OnNextPreviousMatch, true));
Just to note, member function pointers are delegates in D, which combines the 'this' pointer of the object and a context pointer. Since the object is available at run time, such a delegate cannot be used as a template parameter. partial is designed to work with free standing functions. It uses the second template argument as the first parameter to the function. So, there is no consideration for member function calls. Perhaps partial can be improved to handle that case but I don't know whether the 'this' pointer can be added to the delegate easily or at all. Ali
Jun 30 2017
prev sibling parent Balagopal Komarath <baluks gmail.com> writes:
On Friday, 30 June 2017 at 08:43:32 UTC, ct wrote:
 It compiled when I wrote:

 auto on_next_previous = &this.OnNextPreviousMatch;
 entry_.addOnNextMatch(&partial!(on_next_previous, true));
 entry_.addOnPreviousMatch(&partial!(on_next_previous, false));

 But not when I wrote:

 entry_.addOnNextMatch(partial!(&this.OnNextPreviousMatch, 
 true));

 Or

 entry_.addOnNextMatch(partial!(&Editor.OnNextPreviousMatch, 
 true));

 Error: value of 'this' is not known at compile time
In the first snippet, you are passing the local variable on_next_previous by alias to the template and not the function &this.OnNextPreviousMatch. AFAIK, when the partial function is invoked at a later point of time, it will use the value of the variable at the invocation time and not the value of the variable at the time of the invocation of partial! template. The following snippet should clarify this. import std.stdio; import std.traits; template partial(alias f, alias arg1, T = Parameters!f[1]) { auto g(T arg2) { return f(arg1, arg2); } enum partial = &g; } int foo(int x, int y) { writeln("foo"); return x + y; } struct bar { int id; int baz(int x, int y) { writeln("bar.baz", id); return x + y; } } void main() { auto foo2 = partial!(foo, 2); writeln(foo2(3)); auto b = bar(0); auto bbaz = &b.baz; auto bar2 = partial!(bbaz, 2); writeln(bar2(3)); // bar.baz0 5 auto c = bar(1); bbaz = &c.baz; writeln(bar2(3)); // bar.baz1 5 } One might think that in the above code, bar2 is set to the partial function b.baz(2, *). But, it is clear that that is not the case. There is no partially applied function here. When bar2 is invoked, it invokes the function in the variable bbaz with the argument given at the time of the template invocation and the argument given during function invocation. The snippet
 partial!(&this.OnNextPreviousMatch, true)
doesn't work because templates cannot accept runtime values as arguments since they work at compile time. The only things that are available at compile time are symbols and literal values. Hope this makes sense.
Jul 01 2017