Thread overview
Generate a pointer to a method of a struct
Oct 14, 2022
kdevel
Oct 15, 2022
Iain Buclaw
Oct 15, 2022
kdevel
Oct 15, 2022
Jack Pope
Oct 16, 2022
user1234
October 14, 2022

Given a struct S with method foo: Any of these expressions

   &foo
   &S.foo
   &.S.foo

when they occur inside the struct they represent a delegate and not a function pointer. Is it okay to "extract" and use the function pointer from the delegate in this way:

struct S {
   void function () fp;
   void foo ()
   {
      fp = (&bar).funcptr;
   }
   void bar ()
   {
      fp = (&foo).funcptr;
   }
   auto fun () // invocation helper
   {
      if (! fp)
         fp = (&foo).funcptr;
      void delegate () dg;
      dg.ptr = &this;
      dg.funcptr = fp;
      return dg ();
   }
}

unittest {
   S s;
   s.fun;
   s.fun;
}

In [1] Walter suggested to use a "lambda function" which reads (adopted to structs):

struct S {
   :
   void function (ref S) fp;
   :
   void foo () {
      :
      fun = function (ref S self) { return self.bar (); };
      :
   }
   :
}

dmd and gdc optimize the lambda invocations away. Nonetheless the expression looks somewhat too big. To overcome this I tried to generate the function pointer outside of the struct:

auto funcptr (alias method) ()
{
   return &method;
}
      :
      fun = funcptr!bar;
      :

Which works but neither dmd nor gdc were able to optimize the additional function call away. So I replaced the function call with a value:

template funcptr (alias method) {
   immutable funcptr = &method; // (*)
}

That code compiles under gdc 12.1 but I could not find any dmd version which compiles the code. All say

ptrtomethod.d(15): Error: non-constant expression `& bar`

Line 15 is the line I marked with (*). Any comments?

[1] https://www.digitalmars.com/articles/b68.html
Member Function Pointers in D

October 15, 2022

On Friday, 14 October 2022 at 18:34:58 UTC, kdevel wrote:

>

dmd and gdc optimize the lambda invocations away. Nonetheless the expression looks somewhat too big. To overcome this I tried to generate the function pointer outside of the struct:

auto funcptr (alias method) ()
{
   return &method;
}
      :
      fun = funcptr!bar;
      :

Which works but neither dmd nor gdc were able to optimize the additional function call away.

pragma(inline, true)
auto funcptr (alias method) ()

October 15, 2022

On Saturday, 15 October 2022 at 00:31:47 UTC, Iain Buclaw wrote:

> >
auto funcptr (alias method) ()
{
   return &method;
}
      :
      fun = funcptr!bar;
      :

Which works but neither dmd nor gdc were able to optimize the additional function call away.

pragma(inline, true)
auto funcptr (alias method) ()

Thanks. Just found that

template funcptr (alias method) {
   enum funcptr = &method;
}

works on both dmd and gdc. This gives rise to questions:

Is this code expected to compile and pass its unittest?

struct S {
   void bar () { }
}

enum ei = &S.bar;
immutable i = &S.bar;  // line 6
const c = &S.bar;      // line 7

unittest {
   import std.stdio;
   writeln (ei);
   writeln (i);
   writeln (c);
}

gdc passes while dmd says:

$ dmd -unittest -main -run ini
ini.d(6): Error: non-constant expression `& bar`
ini.d(7): Error: non-constant expression `& bar`

Is this consistent?

October 15, 2022
On Saturday, 15 October 2022 at 01:48:15 UTC, kdevel wrote:
> $ dmd -unittest -main -run ini
> ini.d(6): Error: non-constant expression `& bar`
> ini.d(7): Error: non-constant expression `& bar`
> ```
>
> Is this consistent?

I can attest to consistency using ldc. Each of the following prevent function address re-assignment:

  immutable string function() f = &S.bar;
  const string function() f = &S.bar;
  enum f = &S.bar;

In contrast, as would be expected, the following has no such restriction:

  string function() f = &S.bar;

Example:

  struct S {
    string bar(){return "Hello";}
    string foo(){return "Goodbye";}
  }

  void main() {
    string function() f = &S.bar;
    writeln(f, " ", f());
    f = &S.foo;
    writeln(f, " ", f());
  }


October 16, 2022

On Saturday, 15 October 2022 at 01:48:15 UTC, kdevel wrote:

>

Is this consistent?

I think all the compilers should error on expressions like Type.nonStaticMethod and instead there should be a new __traits dedicated to that, especially because this is not a formal parameter.