digitalmars.D.learn - Debug help - opDispatch - unknown member function
- Brother Bill (42/42) Sep 08 https://tour.dlang.org/tour/en/gems/opdispatch-opapply
- monkyyy (4/9) Sep 08 you didnt define "callhome" so the the mixin fails, this
- Brother Bill (3/15) Sep 08 Then I'm not clear what an "unknown" member function name means.
- monkyyy (29/45) Sep 08 ```d
- Brother Bill (51/79) Sep 09 I simplified your example, and manually expanded opDispatch so D
- Brother Bill (3/7) Sep 09 Please provide an example where providing simple names causes
- monkyyy (28/36) Sep 09 ```d
- Dejan Lekic (36/43) Sep 09 Hopefully this slightly modified, and commented version of your
- Brother Bill (42/77) Sep 09 When commenting out the callHome() in struct C, it fails.
- Dejan Lekic (15/17) Sep 09 If C does not have callHome() method, then
- IchorDev (7/9) Sep 09 You can't call a function that doesn't exist. When the function
- monkyyy (5/9) Sep 09 Specs are often declarative but the compiler(especially walters
- Steven Schveighoffer (13/19) Sep 09 You might be expecting `opDispatch` inside `CallLogger` to try
- monkyyy (23/26) Sep 09 Yours still thinking declaratively, that cant be true. The best
- Steven Schveighoffer (5/31) Sep 09 This calls the UFCS versions, because the `opDispatch` version
- monkyyy (18/52) Sep 11 ```d
https://tour.dlang.org/tour/en/gems/opdispatch-opapply This states: "Any unknown member function call to that type is passed to opDispatch, passing the unknown member function's name as a string template parameter." So I tried that. But the compiler didn't like it. How should I play the game of passing in an unknown member function name? ``` import std.stdio; void main() { CallLogger!C l; l.callA(1, 2); l.callB("ABC"); l.callHome("foo", "bar"); // Fails here } struct C { void callA(int i, int j) { } void callB(string s) { } } struct CallLogger(C) { C content; void opDispatch(string name, T...)(T vals) { writeln("called ", name); mixin("content." ~ name)(vals); } } ``` Console output: ``` c:\dev\D\D_templates_tutorial\toy1\source\app.d(8): Error: no property `callHome` for `l` of type `app.CallLogger!(C)` l.callHome("foo", "bar"); ^ ```
Sep 08
On Tuesday, 9 September 2025 at 00:40:31 UTC, Brother Bill wrote:https://tour.dlang.org/tour/en/gems/opdispatch-opapply This states: "Any unknown member function call to that type is passed to opDispatch, passing the unknown member function's name as a string template parameter." [...]you didnt define "callhome" so the the mixin fails, this propagates a "__error" or something, and opDispatch when it contains an error doesnt pass it up the stack
Sep 08
On Tuesday, 9 September 2025 at 00:45:00 UTC, monkyyy wrote:On Tuesday, 9 September 2025 at 00:40:31 UTC, Brother Bill wrote:Then I'm not clear what an "unknown" member function name means. Kindly provide an example.https://tour.dlang.org/tour/en/gems/opdispatch-opapply This states: "Any unknown member function call to that type is passed to opDispatch, passing the unknown member function's name as a string template parameter." [...]you didnt define "callhome" so the the mixin fails, this propagates a "__error" or something, and opDispatch when it contains an error doesnt pass it up the stack
Sep 08
On Tuesday, 9 September 2025 at 01:08:41 UTC, Brother Bill wrote:On Tuesday, 9 September 2025 at 00:45:00 UTC, monkyyy wrote:```d import std; struct Vector(int N,T,string fields){ static foreach(I;0..N){ mixin("T "~fields[I]~";"); } auto opDispatch(string __s__)(){//I suggest a habit of avoiding simple names when generating mixin code return mixin((){ string output="tuple("; foreach(C;__s__){ output~=C; output~=','; } output~=")"; return output; }()); } } unittest{ Vector!(3,int,"xyz") foo; foo.x=5; foo.y=3; foo.yx.writeln; Vector!(4,ubyte,"rgba") bar; bar.bgr.writeln; } ```On Tuesday, 9 September 2025 at 00:40:31 UTC, Brother Bill wrote:Then I'm not clear what an "unknown" member function name means. Kindly provide an example.https://tour.dlang.org/tour/en/gems/opdispatch-opapply This states: "Any unknown member function call to that type is passed to opDispatch, passing the unknown member function's name as a string template parameter." [...]you didnt define "callhome" so the the mixin fails, this propagates a "__error" or something, and opDispatch when it contains an error doesnt pass it up the stack
Sep 08
On Tuesday, 9 September 2025 at 01:24:59 UTC, monkyyy wrote:
```d
import std;
struct Vector(int N,T,string fields){
static foreach(I;0..N){
mixin("T "~fields[I]~";");
}
auto opDispatch(string __s__)(){//I suggest a habit of
avoiding simple names when generating mixin code
return mixin((){
string output="tuple(";
foreach(C;__s__){
output~=C;
output~=',';
}
output~=")";
return output;
}());
}
}
unittest{
Vector!(3,int,"xyz") foo;
foo.x=5;
foo.y=3;
foo.yx.writeln;
Vector!(4,ubyte,"rgba") bar;
bar.bgr.writeln;
}
```
I simplified your example, and manually expanded opDispatch so D
newbies can grok it.
Please explain the opDispatch IIFE and why no semicolon needed at
the end.
```
import std;
// Comment out yx() xor opDispatch()
struct Vector(int N, T, string fields){
int x;
int y;
int z;
// manual expansion of opDispatch
// auto yx() {
// string output = "tuple(";
// foreach (char scv; "yx") {
// output ~= scv;
// output ~= ",";
// }
// output ~= ")";
// writeln(output); // This is not in opDispatch()
// return tuple(3, 5); // Hack to return same result
// }
// I suggest a habit of avoiding simple names when generating
mixin code
auto opDispatch(string __s__)() { // IIFE
writeln("__s__: ", __s__);
return mixin(() {
string output = "tuple(";
foreach (C; __s__){
output ~= C;
output ~= ',';
}
output ~= ")";
return output;
} ());
}
}
void main() {
Vector!(3, int, "xyz") foo;
foo.x = 5; // Standard assignment to known member
foo.y = 3; // Standard assignment to known member
foo.yx.writeln; // yx not a member of Vector, so opDispatch is
called
}}
```
Console output:
```
__s__: yx
Tuple!(int, int)(3, 5)
```
Sep 09
On Tuesday, 9 September 2025 at 01:24:59 UTC, monkyyy wrote:``` // I suggest a habit of avoiding simple names when generating mixin code ```Please provide an example where providing simple names causes 'trouble'.
Sep 09
On Tuesday, 9 September 2025 at 11:57:54 UTC, Brother Bill wrote:On Tuesday, 9 September 2025 at 01:24:59 UTC, monkyyy wrote:```d import std; struct Vector(int N,T,string fields){ static foreach(I;0..N){ mixin("T "~fields[I]~";"); } auto opDispatch(string s)(){//I suggest a habit of avoiding simple names when generating mixin code return mixin((){ string output="tuple("; foreach(C;s){ output~=C; output~=','; } output~=")"; return output; }()); } } unittest{ Vector!(4,int,"xyzs") foo; foo.x=5; foo.y=3; foo.s=7; assert(foo.sx==tuple(7,5)); } `````` // I suggest a habit of avoiding simple names when generating mixin code ```Please provide an example where providing simple names causes 'trouble'.
Sep 09
On Tuesday, 9 September 2025 at 00:40:31 UTC, Brother Bill wrote:https://tour.dlang.org/tour/en/gems/opdispatch-opapply This states: "Any unknown member function call to that type is passed to opDispatch, passing the unknown member function's name as a string template parameter." So I tried that. But the compiler didn't like it. How should I play the game of passing in an unknown member function name?Hopefully this slightly modified, and commented version of your original code will help you understand why your mixin is failing: ```d import std.stdio; void main() { CallLogger!C l; l.callA(1, 2); l.callB("ABC"); // CallLogger does not have method called "callHome", but it has opDispatch, so // the compiler will lower this down to l.opDispatch("callHome", "foo", "bar") l.callHome("foo", "bar"); } struct C { void callA(int i, int j) { } void callB(string s) { } // Your mixin generates code that calls C.callHome which did not exist void callHome(string a, string b) { writeln(a, "/", b); } } struct CallLogger(C) { C content; void opDispatch(string name, T...)(T vals) { writeln("called ", name); // Now it works, because C now has callHome method mixin("content." ~ name)(vals); } } ```
Sep 09
On Tuesday, 9 September 2025 at 09:59:40 UTC, Dejan Lekic wrote:
Hopefully this slightly modified, and commented version of your
original code will
help you understand why your mixin is failing:
```d
import std.stdio;
void main() {
CallLogger!C l;
l.callA(1, 2);
l.callB("ABC");
// CallLogger does not have method called "callHome", but
it has opDispatch, so
// the compiler will lower this down to
l.opDispatch("callHome", "foo", "bar")
l.callHome("foo", "bar");
}
struct C {
void callA(int i, int j) {
}
void callB(string s) {
}
// Your mixin generates code that calls C.callHome which
did not exist
void callHome(string a, string b) {
writeln(a, "/", b);
}
}
struct CallLogger(C) {
C content;
void opDispatch(string name, T...)(T vals) {
writeln("called ", name);
// Now it works, because C now has callHome method
mixin("content." ~ name)(vals);
}
}
```
When commenting out the callHome() in struct C, it fails.
Obviously if callHome() is explicitly created, it works.
```
import std.stdio;
void main() {
CallLogger!C l;
l.callA(1, 2);
l.callB("ABC");
// CallLogger does not have method called "callHome", but it
has opDispatch, so
// the compiler will lower this down to
l.opDispatch("callHome", "foo", "bar")
l.callHome("foo", "bar");
}
struct C {
void callA(int i, int j) {
}
void callB(string s) {
}
// Your mixin generates code that calls C.callHome which did
not exist
// void callHome(string a, string b) {
// writeln(a, "/", b);
// }
}
struct CallLogger(C) {
C content;
void opDispatch(string name, T...)(T vals) {
writeln("called ", name);
// Now it works, because C now has callHome method
mixin("content." ~ name)(vals);
}
}
```
Console contents:
```
c:\dev\D\D_templates_tutorial\toy1\source\app.d(10): Error: no
property `callHome` for `l` of type `app.CallLogger!(C)`
l.callHome("foo", "bar");
^
```
Sep 09
On Tuesday, 9 September 2025 at 12:04:07 UTC, Brother Bill wrote:When commenting out the callHome() in struct C, it fails. Obviously if callHome() is explicitly created, it works.If C does not have callHome() method, then ```d mixin("content." ~ name)(vals); ``` will simply fail, because that line effectively generates this code: ```d content.callHome("foo", "bar"); ``` Since content is of type C, which does not have callHome method, it will fail, and is expected to fail. Sorry I can't think of a better explanation than what I tried in my previous post... Since I can't come up with a better explanation I will stop writing in this thread. Good luck!
Sep 09
On Tuesday, 9 September 2025 at 12:04:07 UTC, Brother Bill wrote:When commenting out the callHome() in struct C, it fails.You can't call a function that doesn't exist. When the function doesn't exist, you can't call it.Obviously if callHome() is explicitly created, it works.*Explicitly* created? You can't just call a non-existent function and expect the compiler to generate it for you. You would need to have an `opDispatch` in `struct C` in order to do what you seem to be expecting to happen.
Sep 09
On Tuesday, 9 September 2025 at 00:40:31 UTC, Brother Bill wrote:https://tour.dlang.org/tour/en/gems/opdispatch-opapply This states: "Any unknown member function call to that type is passed to opDispatch, passing the unknown member function's name as a string template parameter."Specs are often declarative but the compiler(especially walters compiler) and the machine it run on is imperative It should say "if overload resolution inside a struct is failing, try a hack where an opDispatch is called"
Sep 09
On Tuesday, 9 September 2025 at 00:40:31 UTC, Brother Bill wrote:
```
c:\dev\D\D_templates_tutorial\toy1\source\app.d(8): Error: no
property `callHome` for `l` of type `app.CallLogger!(C)`
l.callHome("foo", "bar");
^
```
You might be expecting `opDispatch` inside `CallLogger` to try
and build `opDispatch!("callHome")("foo", "bar")`.
The thing is, it does. But when the compiler encounters failures,
it means that it assumes `opDispatch` was not designed to handle
that function, and it moves on to other options (UFCS maybe).
This is a long standing issue, and one that is very difficult to
fix due to the way name lookup rules are working in the compiler.
In short `opDispatch` only is valid if it compiles. If it doesn't
compile, it's as if it doesn't exist. This limitation is likely
with us until someone can rework how the name lookups and IFTI
works.
-Steve
Sep 09
On Tuesday, 9 September 2025 at 19:17:11 UTC, Steven Schveighoffer wrote:In short `opDispatch` only is valid if it compiles. If it doesn't compile, it's as if it doesn't exist.Yours still thinking declaratively, that cant be true. The best description of its behavior is that it discards errors. ```d import std; enum counter=cast(immutable(void)*)[0].ptr; auto getcount()=>(*(cast(int*)counter)); auto count()=>(*(cast(int*)counter))++; struct foo{ void opDispatch(string s)(){ enum _=count(); static assert(0); } } void bar(foo){} void foobar(foo){} unittest{ foo().bar; foo().foobar; getcount.writeln;//2 } ```
Sep 09
On Tuesday, 9 September 2025 at 20:08:06 UTC, monkyyy wrote:On Tuesday, 9 September 2025 at 19:17:11 UTC, Steven Schveighoffer wrote:This calls the UFCS versions, because the `opDispatch` version does not compile. The other thing is just a bug. -SteveIn short `opDispatch` only is valid if it compiles. If it doesn't compile, it's as if it doesn't exist.Yours still thinking declaratively, that cant be true. The best description of its behavior is that it discards errors. ```d import std; enum counter=cast(immutable(void)*)[0].ptr; auto getcount()=>(*(cast(int*)counter)); auto count()=>(*(cast(int*)counter))++; struct foo{ void opDispatch(string s)(){ enum _=count(); static assert(0); } } void bar(foo){} void foobar(foo){} unittest{ foo().bar; foo().foobar; getcount.writeln;//2 } ```
Sep 09
On Tuesday, 9 September 2025 at 20:56:19 UTC, Steven Schveighoffer wrote:On Tuesday, 9 September 2025 at 20:08:06 UTC, monkyyy wrote:```d import std; struct foo{ void opDispatch(string s)(){ pragma(msg,"hi"); static assert(0); } } void bar(foo){} unittest{ foo().bar;//prints hi } ``` Even if you were egregious bigoted to some features out of some kind of spec purity belief; its demonstrable with entirely in spec behaviorOn Tuesday, 9 September 2025 at 19:17:11 UTC, Steven Schveighoffer wrote:This calls the UFCS versions, because the `opDispatch` version does not compile. The other thing is just a bug. -SteveIn short `opDispatch` only is valid if it compiles. If it doesn't compile, it's as if it doesn't exist.Yours still thinking declaratively, that cant be true. The best description of its behavior is that it discards errors. ```d import std; enum counter=cast(immutable(void)*)[0].ptr; auto getcount()=>(*(cast(int*)counter)); auto count()=>(*(cast(int*)counter))++; struct foo{ void opDispatch(string s)(){ enum _=count(); static assert(0); } } void bar(foo){} void foobar(foo){} unittest{ foo().bar; foo().foobar; getcount.writeln;//2 } ```
Sep 11









Brother Bill <brotherbill mail.com> 