Bug 6434 – opDispatch must be considered before alias this.

Status
RESOLVED
Resolution
FIXED
Severity
enhancement
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2011-08-03T06:14:26Z
Last change time
2019-09-21T03:34:09Z
Keywords
patch, rejects-valid
Assigned to
No Owner
Creator
Gor Gyolchanyan
See also
https://issues.dlang.org/show_bug.cgi?id=20233

Comments

Comment #0 by gor — 2011-08-03T06:14:26Z
When a class or struct has an opDispatch and an alias this, the alias this is considered first and a member access gives "no such property" error: struct A { Variant i; alias i this; void opDispatch(string name)() { } } unittest { A a; a.weird; // no property 'weird' for type 'VariantN!(maxSize)' }
Comment #1 by k.hara.pg — 2011-08-15T22:15:40Z
Comment #2 by samukha — 2011-08-16T02:39:02Z
I am not sure. opDispatch is meant to be a fallback mechanism used after all regular lookups fail. For example, one intended use of opDispatch is to dynamically handle calls to members unavailable statically. With "alias this" given the lowest priority, one would need to manually forward calls to inherited members: struct A { Variant i; alias i this; auto opDispatch(string name, A...)(auto ref A args) { static if (isCallableOnI!(name, A))) mixin("return i." ~ name ~ "(args);"); // this shouldn't be necessary else return dispatchDynamically(name, toVariants(args)); } } So the bug is in opDispatch not being considered after "alias this" lookup fails, and not in the order of lookups.
Comment #3 by samukha — 2011-08-16T03:07:32Z
On the other hand, opDispatch considered first gives much more flexibility. Then, what to do with regular inheritance: class A { int foo(); } class B : A { void opDispatch(string name)() { } } auto b = new B; b.foo(); Should foo be opDispatched?
Comment #4 by gor — 2011-08-16T03:55:33Z
I agree. This would make more sense. Let the opDispatch be used after alias this. (In reply to comment #2) > I am not sure. opDispatch is meant to be a fallback mechanism used after all > regular lookups fail. For example, one intended use of opDispatch is to > dynamically handle calls to members unavailable statically. With "alias this" > given the lowest priority, one would need to manually forward calls to > inherited members: > > struct A > { > Variant i; > alias i this; > > auto opDispatch(string name, A...)(auto ref A args) > { > static if (isCallableOnI!(name, A))) > mixin("return i." ~ name ~ "(args);"); // this shouldn't be > necessary > else > return dispatchDynamically(name, toVariants(args)); > } > } > > So the bug is in opDispatch not being considered after "alias this" lookup > fails, and not in the order of lookups. I think all VISIBLE members should be used before opDispatch. (In reply to comment #3) > On the other hand, opDispatch considered first gives much more flexibility. > Then, what to do with regular inheritance: > > class A > { > int foo(); > } > > class B : A > { > void opDispatch(string name)() > { > } > } > > auto b = new B; > b.foo(); > > Should foo be opDispatched?
Comment #5 by bugzilla — 2011-08-25T17:38:45Z
Comment #6 by k.hara.pg — 2011-08-28T00:30:37Z
From here discussion, I have posted newer version of pull request. opDispatch should be considered *after* failing alias this lookup. https://github.com/D-Programming-Language/dmd/pull/349
Comment #7 by k.hara.pg — 2011-10-23T22:20:39Z
*** Issue 4224 has been marked as a duplicate of this issue. ***
Comment #8 by k.hara.pg — 2011-10-23T22:29:00Z
Reopened pull request. https://github.com/D-Programming-Language/dmd/pull/349 Points: 1. alias this lookup should be considered first. It is the synonym of super-class. 2. If alias this lookup fails, *most derived* opDispatch should be used. // From https://github.com/D-Programming-Language/dmd/pull/349#issuecomment-1923037 struct A { int opDispatch(string s)() { return 1; } } struct B { A a; alias a this; int opDispatch(string s)() if (s == "bsfunc") { return 2; } } void main() { B b; assert(b.bsfunc() == 2); assert(b.notfoundanywhere() == 1); // *1 } The most derived opDispatch from B is B.opDispatch, then b.xxx is always transformed to b.opDispatch!("xxx"). Therefore, line *1 doesn't compile, and A.opDispatch is never used.
Comment #9 by schveiguy — 2011-10-24T09:09:25Z
I disagree that alias this should be preferred. From my description in bug 4989: > IMO, opDispatch should be preferred over the alias this'd member. Simply > because it's possible (though ugly) to select which opDispatch functions > compile, but it's impossible to selectively pick members to compile via alias > this. opDispatch is a tool to help generate dynamic function call bindings. It should not be ignored in the most derived struct, under any circumstances. Otherwise, wrapping another type will be a nightmare. See my example in 4989. To make opDispatch override the 'base' opDispatch, but not have the derived opDispatch be able to override the base normal methods is also very error-prone. It is not the compiler's decision to make on what priority opDispatch has over aliased members, regardless of whether they are declared or implied. Adding a declared function will inadvertently change code paths for those function calls, without any warning.
Comment #10 by lovelydear — 2012-04-27T07:48:07Z
The program in description now compiles and runs on 2.059
Comment #11 by bugzilla — 2013-03-06T23:25:22Z
I agree with Steven. opDispatch should be considered first. The rationale is straightforward - the wrapper gets to decide, not the wrappee, what opDispatch means. If the wrapper wants to forward to the alias this, it can do so with an appropriate implementation of opDispatch. But if alias this takes precedence, one is stuck. So, barring a more compelling rationale for alias this overriding, this enhancement should be rejected. I also marked this as an enhancement.
Comment #12 by razvan.nitu1305 — 2018-10-11T17:06:06Z
opDispatch is considered before alias this. PR : https://github.com/dlang/dmd/pull/315 Closing as fixed.