Thread overview
Problem of undefined behaviour with overloaded methods and overloaded delegate's invokers
Aug 01, 2017
knex
Aug 01, 2017
knex
Aug 01, 2017
John Colvin
Aug 02, 2017
knex
August 01, 2017
I came across a strange thing and I am not sure if this is a bug or just an undefined behaviour of a compiler. Here is some sample code to present the case:

//

alias BoolFirst = void delegate(bool b, string s);
alias StringFirst = void delegate(string s, bool b);

class Caller {
    void call(BoolFirst bs) { bs(true, "text"); }
    void call(StringFirst sb) { sb("text", true); }
}

class Writer {
    import std.stdio;
    void write(bool b, string s) { writeln("bool+string:", b, "/", s); }
    void write(string s, bool b) { writeln("string+bool:", s, "/", b); }
}

void main() {
    new Caller().call(&new Writer().write);
}

//

As you can see, I have two classes, both having two overloaded methods. Writer has some dummy printing methods for bool and string, differing with the order of the arguments, while Caller takes one of these methods as a delegate and invokes it. In main() I create objects of these classes and call Caller's call() with Writer's write().

But - as far as I understand - this call is ambiguous, and compiler does not know what should be done here: calling call/write pair for bool+string or for string+bool parameters. Nevertheless the code compiles and the program runs the fist variant. The funny thing is that swapping write() methods in the source file causes calling the second one. But OK, suppose that this is and should be treated as an undefined behaviour. What is actually disturbing here, is that casting like c.call(cast(BoolFirst) &w.write) compiles, although is not necessary, because not casting works the same way, but casting c.call(cast(StringFirst) &w.write) - which should help here in calling string+bool variant - does not compile, and the compiler says that "Caller.call called with argument types (void delegate(string s, bool b)) matches both (...)", which is clearly true. Moreover, swapping write() methods again causes the exact opposite behaviour: cast(StringFirst) compiles, but is useless, and cast(BoolFirst) does not compile at all.

So, is this a bug, or am I just not getting something? In the first case, is there some kind of a workaround for the possibility of calling both variants (without changing the code of Caller and Writer classes)? In the last case, how should I do it properly?

I am using DMD32 D Compiler v2.075.0 on Linux.
August 01, 2017
Erratum:
which is clearly true ---> which is clearly untrue
August 01, 2017
On Tuesday, 1 August 2017 at 11:07:59 UTC, knex wrote:
> I came across a strange thing and I am not sure if this is a bug or just an undefined behaviour of a compiler. Here is some sample code to present the case:
>
> //
>
> alias BoolFirst = void delegate(bool b, string s);
> alias StringFirst = void delegate(string s, bool b);
>
> class Caller {
>     void call(BoolFirst bs) { bs(true, "text"); }
>     void call(StringFirst sb) { sb("text", true); }
> }
>
> class Writer {
>     import std.stdio;
>     void write(bool b, string s) { writeln("bool+string:", b, "/", s); }
>     void write(string s, bool b) { writeln("string+bool:", s, "/", b); }
> }
>
> void main() {
>     new Caller().call(&new Writer().write);
> }
>
> //
>
> As you can see, I have two classes, both having two overloaded methods. Writer has some dummy printing methods for bool and string, differing with the order of the arguments, while Caller takes one of these methods as a delegate and invokes it. In main() I create objects of these classes and call Caller's call() with Writer's write().
>
> But - as far as I understand - this call is ambiguous, and compiler does not know what should be done here: calling call/write pair for bool+string or for string+bool parameters. Nevertheless the code compiles and the program runs the fist variant. The funny thing is that swapping write() methods in the source file causes calling the second one. But OK, suppose that this is and should be treated as an undefined behaviour. What is actually disturbing here, is that casting like c.call(cast(BoolFirst) &w.write) compiles, although is not necessary, because not casting works the same way, but casting c.call(cast(StringFirst) &w.write) - which should help here in calling string+bool variant - does not compile, and the compiler says that "Caller.call called with argument types (void delegate(string s, bool b)) matches both (...)", which is clearly true. Moreover, swapping write() methods again causes the exact opposite behaviour: cast(StringFirst) compiles, but is useless, and cast(BoolFirst) does not compile at all.
>
> So, is this a bug, or am I just not getting something? In the first case, is there some kind of a workaround for the possibility of calling both variants (without changing the code of Caller and Writer classes)? In the last case, how should I do it properly?
>
> I am using DMD32 D Compiler v2.075.0 on Linux.

looks like a bug to me. Please report at issues.dlang.org
August 02, 2017
On Tuesday, 1 August 2017 at 11:30:07 UTC, John Colvin wrote:
> looks like a bug to me. Please report at issues.dlang.org

Let it be, then. Reported at https://issues.dlang.org/show_bug.cgi?id=17710