Thread overview
mir.algebraic: Visitor cannot be called
Dec 09, 2020
Andre Pany
Dec 10, 2020
9il
Dec 10, 2020
Andre Pany
December 09, 2020
Hi,

I want to port some Python coding and try have as much similiar coding as
possible.

I thought I can have a mir variant which stores either class A or B
and I can call at runtime a method like this:

```
/+ dub.sdl:
	name "app"
	dependency "mir-core" version="1.1.51"
+/

import std.stdio: writeln;
import mir.algebraic;

class A {
	void foo(int i){writeln("A.foo");}
}

class B {
	void foo(int i, string s){writeln("B.foo");}
}

void main() {
	Variant!(A,B) v = new A();
	v.foo(3);
}
```

But it fails with:
Error: static assert:  "Algebraic!(A, B): the visitor cann't be caled with arguments (B, int)"

The error message seems strange. Is the behavior I want somehow possible?
(At runtime I know whether I have an object of A or B and will only call
with the correct method signature).

Kind regards
André
December 10, 2020
On Wednesday, 9 December 2020 at 14:34:18 UTC, Andre Pany wrote:
> Hi,
>
> I want to port some Python coding and try have as much similiar coding as
> possible.
>
> I thought I can have a mir variant which stores either class A or B
> and I can call at runtime a method like this:
>
> ```
> /+ dub.sdl:
> 	name "app"
> 	dependency "mir-core" version="1.1.51"
> +/
>
> import std.stdio: writeln;
> import mir.algebraic;
>
> class A {
> 	void foo(int i){writeln("A.foo");}
> }
>
> class B {
> 	void foo(int i, string s){writeln("B.foo");}
> }
>
> void main() {
> 	Variant!(A,B) v = new A();
> 	v.foo(3);
> }
> ```
>
> But it fails with:
> Error: static assert:  "Algebraic!(A, B): the visitor cann't be caled with arguments (B, int)"
>
> The error message seems strange. Is the behavior I want somehow possible?
> (At runtime I know whether I have an object of A or B and will only call
> with the correct method signature).
>
> Kind regards
> André

For .member access mir.algebraic checks at compile time that all underlying types (except typeof(null)) can be called with provided arguments. It is kind of API protection.

Alternatives:

With compile-time known type
```
v.get!A.foo(3); // will throw if it isn't A
v.trustedGet!A.foo(3); // will assert if it isn't A
```

Without compile-time known type
```
v.tryGetMember!"foo"(3); // will throw if it isn't A
v.optionalGetMember!"foo"(3); // will return null Nullable!void of it isn't A
```

tryGetMember and optionalGetMember are alternative visitor handlers in mir.algebraic.

Kind regards,
Ilya

December 10, 2020
On Thursday, 10 December 2020 at 05:49:12 UTC, 9il wrote:
> On Wednesday, 9 December 2020 at 14:34:18 UTC, Andre Pany wrote:
>> [...]
>
> For .member access mir.algebraic checks at compile time that all underlying types (except typeof(null)) can be called with provided arguments. It is kind of API protection.
>
> Alternatives:
>
> With compile-time known type
> ```
> v.get!A.foo(3); // will throw if it isn't A
> v.trustedGet!A.foo(3); // will assert if it isn't A
> ```
>
> Without compile-time known type
> ```
> v.tryGetMember!"foo"(3); // will throw if it isn't A
> v.optionalGetMember!"foo"(3); // will return null Nullable!void of it isn't A
> ```
>
> tryGetMember and optionalGetMember are alternative visitor handlers in mir.algebraic.
>
> Kind regards,
> Ilya

Fantastic, thanks a lot!

Kind regards
André