www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Generate a pointer to a method of a struct

reply kdevel <kdevel vogtner.de> writes:
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
Oct 14 2022
parent reply Iain Buclaw <ibuclaw gdcproject.org> writes:
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) ()
Oct 14 2022
parent reply kdevel <kdevel vogtner.de> writes:
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?
Oct 14 2022
next sibling parent Jack Pope <zedlan invec.net> writes:
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()); }
Oct 15 2022
prev sibling parent user1234 <user1234 12.de> writes:
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.
Oct 15 2022