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)'
}
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?
*** 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