Hi there,
I just started the registration process for InstanceDispatch.jl, a single-macro package that writes for you a method that dispatches on methods with value-type from a type that defines a Base.instances
method (typically an @enum
). Say you have a function that behaves differently depending on a flag that has been passed to it (typically a finite state machine). For example
@enum GreetEnum Hello Goodbye
function greet(::Val{Hello}, who)
return "Hello " * who
end
function greet(::Val{Goodbye}, who)
return "Goodbye " * who
end
In your state machine you would like to store the flag as an instance of the enum, but then simply calling greet(Val(state), somename)
is not type stable. This package automates the tedious task of writing and maintaining the following method:
function greet(e::GreetEnum, who)
if e == Hello
return greet(Val(Hello), who)
elseif e == Goodbye
return greet(Val(Goodbye), who)
else
end
end
Instead you can simply write:
@instancedispatch greet(::GreetEnum, who)
There’s also the possibility of dispatching on multiple enums, you can check the documentation!
7 Likes
This reminds me of ValSplit.jl
2 Likes
Oh! indeed, I did not find this package when I was looking for a solution to this problem. This is essentially the same thing for symbol-based value types. I will add a link to ValSplit,jl in the README file.
1 Like
Both InstanceDispatch.jl
and ValSplit.jl
are useful. I want something very similar, but I don’t think they work for me. This is what I am doing:
julia> struct Obj{S} end;
julia> Obj(s::Symbol) = Obj{s}();
julia> Base.:*(::Obj{:A}, n) = n * 2;
julia> Base.:*(::Obj{:B}, n) = n * 3;
julia> Obj(:A) * 2
4
julia> Obj(:B) * 2
6
I could write methods for Base.:*
for ::Val{<:Symbol}
. But this would be type piracy. Furthermore, I have additional semantics for Obj{S}
. I don’t want to confuse this with Val
.
Maybe something like ValSplit
that allows you to specify the type in the macro (or some macro). Following the example in ValSplit
, instead of
@valsplit function soundof(Val(animal::Symbol)) ...
you would have
@valsplit Obj function soundof(Obj(animal::Symbol)) ...
EDIT: I bet no one here is smart enough to modify ValSplit.jl to do this. Yeah, a waste of time mentioning it.
heh, JK, I am considering looking into it.
Oh well, that turned out to be an interesting problem. I just pushed a fix to InstanceDispatch.jl that allows using dotted function names. As soon as this patch lands in Julia’s registry, you can solve your problem by doing something like:
julia> using InstanceDispatch
julia> @enum ObjLabel A B
julia> struct Obj
label::ObjLabel
end
julia> Base.:*(::Val{A}, n) = n * 2
julia> Base.:*(::Val{B}, n) = n * 3
julia> @instancedispatch (Base.:*)(::ObjLabel, n)
julia> Base.:*(o::Obj, n) = Base.:*(o.label, n)
julia> Obj(A) * 2
4
julia> Obj(B) * 2
6
julia> # Or, if you prefer the type annotation solution
struct Obj2{Label} end
julia> Obj2(l::ObjLabel) = Obj2{l}()
Obj2
julia> Base.:*(::Obj2{Label}, n) where {Label} = Base.:*(Label, n)
julia> Obj2(A) * 2
4
julia> Obj2(B) * 2
6
As for modifying ValSplit.jl, if I recall correctly the code is not too complicated; you probably want to generalize it by tweaking valarg_params
to add an argument with the object type that replaces Val
.
1 Like
Still interesting since ValSplit.jl doesn’t seem to work on Julia 1.12 
That was shameless nerdsniping, on my part.
I am eager to try this
2 Likes
If that makes the package better I have no problem with nerd-sniping. 