Bug 2557 – inconsistent behavior when taking reference to member without instance

Status
RESOLVED
Resolution
WONTFIX
Severity
normal
Priority
P2
Component
dmd
Product
D
Version
D1 (retired)
Platform
All
OS
All
Creation time
2009-01-05T09:50:10Z
Last change time
2017-12-05T00:34:49Z
Keywords
accepts-invalid
Assigned to
No Owner
Creator
Brian
See also
https://issues.dlang.org/show_bug.cgi?id=3720

Attachments

IDFilenameSummaryContent-TypeSize
285method_ref.dtest caseapplication/octet-stream579

Comments

Comment #0 by d — 2009-01-05T09:50:10Z
See attached test case. When the current context has no 'this', taking a reference to a member function works correctly. However inside another class' instance method, the same code throws an error, seemingly trying to automatically apply the current 'this' even though I'm trying to take a function, not a delegate. The inconsistent behavior is buggy. I would argue towards allowing the reference to be taken in the 'this' instance, since it can be useful when building up delegates as shown in the test case. Obviously pointless here, but I discovered the bug when trying to refactor my code for walking over a collection calling a given method after applying a filtering function, so there is real-world call for doing this.
Comment #1 by d — 2009-01-05T09:50:45Z
Created attachment 285 test case
Comment #2 by smjg — 2009-01-11T17:28:44Z
It doesn't work. "works" means "behaves correctly", not "compiles without error". The code is wrong regardless of whether dofun is static or not. A.fun needs an object of type A. But it doesn't have one. ---------- bz2557.d(21): Error: this for fun needs to be type A not type method_ref.B bz2557.d(21): Error: cannot implicitly convert expression (&this.fun) of type void delegate() to void function() ----------
Comment #3 by 2korden — 2009-01-11T17:42:09Z
(In reply to comment #2) > The code is wrong regardless of whether dofun is static or not. A.fun needs an > object of type A. But it doesn't have one. > I'm not so sure. Object of type A is provided by these two lines of code: A a = new A; dg2.ptr = cast(void*)a;
Comment #4 by smjg — 2009-01-11T19:09:19Z
But your code tries to use &A.fun, not &a.fun. For &A.fun to make any sense with A being a type, fun would have to be a static method of A.
Comment #5 by 2korden — 2009-01-12T00:26:43Z
That's a feature! Even if method is not static, it still has a single unique body. If so, why can't you take its address?
Comment #6 by smjg — 2009-01-12T03:09:54Z
(In reply to comment #5) > That's a feature! Even if method is not static, it still has a single unique > body. If so, why can't you take its address? http://www.digitalmars.com/d/1.0/type.html#delegates "There are no pointers-to-members in D, but a more useful concept called delegates are supported." Even if there were, the type would not be void function() as is declared in the attached code, but rather void function(A) or perhaps something like void A.function() akin to C++ notation (IIRC) void (A::*)() Maybe void function() would work if the calling convention specifies that the context pointer be always passed in a register that is never used for any other kind of function argument, but that isn't the case in the current ABI.
Comment #7 by 2korden — 2009-01-12T04:53:45Z
Makes sense. Perhaps, another enhancement report should be created with a request to change typeof(&A.foo) from void function() to void delegate() with a dg.ptr being null.
Comment #8 by smjg — 2009-01-12T07:15:21Z
(In reply to comment #7) > Makes sense. Perhaps, another enhancement report should be created with a > request to change typeof(&A.foo) from void function() to void delegate() with a > dg.ptr being null. That would still be prone to accidental misuse IMO. Really, D should do one of the following: (a) add method pointer types (b) define &A.foo to be of a type that has the context pointer as just another parameter (which might break if ABI changes to support function-to-delegate conversion are implemented) (c) (continue to) disallow &A.foo altogether
Comment #9 by d — 2009-01-14T16:46:46Z
> It doesn't work. "works" means "behaves correctly", not "compiles without error". I understand the difference between "works" and "compiles', it does work in my testing. The method body I'm taking a pointer to is empty in the test case but I first ran into this inconsistency while refactoring some code, where the method body was *not* empty and the code inside the method executed correctly. Whether it *should* work or not is certainly debatable, but I find it a useful behavior except for the inconsistency shown.
Comment #10 by slavo5150 — 2017-12-05T00:30:19Z
For convenience, I'm adding the source code from the original post's attachment here: module method_ref; class A { void fun() {} } void main() { /* This works correctly and can sometimes be very useful */ A a = new A; void function() fn1 = &A.fun; void delegate() dg1; dg1.ptr = cast(void*)a; dg1.funcptr = fn1; dg1(); } class B { /+ static /* works if static */ +/ void dofun() { /* Error: this for fun needs to be type A not type method_ref.B */ A a = new A; void function() fn2 = &A.fun; void delegate() dg2; dg2.ptr = cast(void*)a; dg2.funcptr = fn2; dg2(); } } It can be tested online here: https://run.dlang.io/is/9GAvd4
Comment #11 by slavo5150 — 2017-12-05T00:34:33Z
I tested the test case with DMD 2.077.1 and it correctly rejects taking a reference to a non-static member function through the type Also, the "Version" for this PR is listed as "D1 (Retired)". It is my understanding that D1 is no longer supported, so closing this issue.