Thread overview
How to partially apply member functions?
Jun 29, 2017
ct
Jun 29, 2017
ct
Jun 29, 2017
ct
Jun 29, 2017
Andrea Fontana
Jun 30, 2017
ct
Jun 30, 2017
Ali Çehreli
Jul 01, 2017
Balagopal Komarath
June 29, 2017
I have something similar to the following:

class Editor {
  void OnNextPreviousMatch(bool is_forward, SearchEntry entry) {
}
}
June 29, 2017
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)'
June 29, 2017
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));
June 29, 2017
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
June 30, 2017
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


June 30, 2017
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

July 01, 2017
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.