# \[ANN\] InstanceDispatch.jl: Dispatch-on-value with anyting that defines a \`Base.instances\` method

**URL:** https://discourse.julialang.org/t/ann-instancedispatch-jl-dispatch-on-value-with-anyting-that-defines-a-base-instances-method/130838
**Category:** Package Announcements
**Tags:** package, dispatch, val, enum
**Created:** [July 18, 2025, 8:13am UTC](https://discourse.julialang.org/t/ann-instancedispatch-jl-dispatch-on-value-with-anyting-that-defines-a-base-instances-method/130838 "2025-07-18T08:13:57Z")
**Posts on this page:** 9
**Page:** 1

<div class="post-metadata">

### Author: ![klafyvel](https://avatars.discourse-cdn.com/v4/letter/k/a587f6/32.png) [@klafyvel](https://discourse.julialang.org/u/klafyvel)
#### Post date: [July 18, 2025, 8:13am UTC](https://discourse.julialang.org/t/ann-instancedispatch-jl-dispatch-on-value-with-anyting-that-defines-a-base-instances-method/130838/1 "2025-07-18T08:13:57Z")

</div>

Hi there,  
I just started the registration process for [InstanceDispatch.jl](https://github.com/Klafyvel/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

```julia
@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:

```julia
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:

```julia
@instancedispatch greet(::GreetEnum, who)

```

There’s also the possibility of dispatching on multiple enums, you can check the [documentation](https://klafyvel.github.io/InstanceDispatch.jl/dev/)!

---

<div class="post-metadata">

### Author: ![jishnub](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jishnub/32/33620_2.png) [@jishnub](https://discourse.julialang.org/u/jishnub)
#### Post date: [July 19, 2025, 1:30pm UTC](https://discourse.julialang.org/t/ann-instancedispatch-jl-dispatch-on-value-with-anyting-that-defines-a-base-instances-method/130838/2 "2025-07-19T13:30:37Z")

</div>

This reminds me of ValSplit.jl

---

<div class="post-metadata">

### Author: ![klafyvel](https://avatars.discourse-cdn.com/v4/letter/k/a587f6/32.png) [@klafyvel](https://discourse.julialang.org/u/klafyvel)
#### Post date: [July 19, 2025, 2:36pm UTC](https://discourse.julialang.org/t/ann-instancedispatch-jl-dispatch-on-value-with-anyting-that-defines-a-base-instances-method/130838/3 "2025-07-19T14:36:49Z")

</div>

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.

---

<div class="post-metadata">

### Author: ![jlapeyre](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jlapeyre/32/4514_2.png) [@jlapeyre](https://discourse.julialang.org/u/jlapeyre)
#### Post date: [August 2, 2025, 3:15pm UTC](https://discourse.julialang.org/t/ann-instancedispatch-jl-dispatch-on-value-with-anyting-that-defines-a-base-instances-method/130838/4 "2025-08-02T15:15:12Z")

</div>

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
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

```julia
@valsplit function soundof(Val(animal::Symbol)) ...

```

you would have

```julia
@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.

---

<div class="post-metadata">

### Author: ![klafyvel](https://avatars.discourse-cdn.com/v4/letter/k/a587f6/32.png) [@klafyvel](https://discourse.julialang.org/u/klafyvel)
#### Post date: [August 3, 2025, 9:09am UTC](https://discourse.julialang.org/t/ann-instancedispatch-jl-dispatch-on-value-with-anyting-that-defines-a-base-instances-method/130838/5 "2025-08-03T09:09:25Z")

</div>

Oh well, that turned out to be an interesting problem. I just pushed [a fix to InstanceDispatch.jl that allows using dotted function names](https://github.com/Klafyvel/InstanceDispatch.jl/commit/e4b22548a2215d4678457427e086b868e8ba0150). As soon as this patch lands in Julia’s registry, you can solve your problem by doing something like:

```julia-repl
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`.

---

<div class="post-metadata">

### Author: ![mofeing](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mofeing/32/47619_2.png) [@mofeing](https://discourse.julialang.org/u/mofeing)
#### Post date: [August 3, 2025, 8:40pm UTC](https://discourse.julialang.org/t/ann-instancedispatch-jl-dispatch-on-value-with-anyting-that-defines-a-base-instances-method/130838/6 "2025-08-03T20:40:47Z")

</div>

Still interesting since ValSplit.jl doesn’t seem to work on Julia 1.12 😔

---

<div class="post-metadata">

### Author: ![jlapeyre](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jlapeyre/32/4514_2.png) [@jlapeyre](https://discourse.julialang.org/u/jlapeyre)
#### Post date: [August 4, 2025, 3:25am UTC](https://discourse.julialang.org/t/ann-instancedispatch-jl-dispatch-on-value-with-anyting-that-defines-a-base-instances-method/130838/7 "2025-08-04T03:25:30Z")

</div>

> [@klafyvel](#):
>
> Oh well, that turned out to be an interesting problem

That was shameless nerdsniping, on my part. 😉 I am eager to try this

---

<div class="post-metadata">

### Author: ![klafyvel](https://avatars.discourse-cdn.com/v4/letter/k/a587f6/32.png) [@klafyvel](https://discourse.julialang.org/u/klafyvel)
#### Post date: [August 4, 2025, 6:28am UTC](https://discourse.julialang.org/t/ann-instancedispatch-jl-dispatch-on-value-with-anyting-that-defines-a-base-instances-method/130838/8 "2025-08-04T06:28:34Z")

</div>

If that makes the package better I have no problem with nerd-sniping. 🙂

---

<div class="post-metadata">

### Author: ![klafyvel](https://avatars.discourse-cdn.com/v4/letter/k/a587f6/32.png) [@klafyvel](https://discourse.julialang.org/u/klafyvel)
#### Post date: [August 24, 2026, 12:56pm UTC](https://discourse.julialang.org/t/ann-instancedispatch-jl-dispatch-on-value-with-anyting-that-defines-a-base-instances-method/130838/9 "2026-08-24T12:56:28Z")

</div>

Hi! Just an update, one year later, to say that I am still working on the package and have been using it quite a lot. I especially love using it to write parsers, and this winter I was able to leverage it to write a JSON parsers (for fun).

Among other things, this year I improved type inference, an added support for annotation of the return type [in v0.2](https://github.com/Klafyvel/InstanceDispatch.jl/releases/tag/v0.2.0), fixed some edge cases [in v0.3.1](https://github.com/Klafyvel/InstanceDispatch.jl/releases/tag/v0.3.1) and [v0.3.2](https://github.com/Klafyvel/InstanceDispatch.jl/releases/tag/v0.3.2), and added the possibility to run some arbitrary code before dispatch [in v0.3.3](https://github.com/Klafyvel/InstanceDispatch.jl/releases/tag/v0.3.3).

In particular, the latter allows writing something like:

```julia-auto
@enum GreetEnum Hello Goodbye
function greet(::Val{Hello}, who)
    return "Hello " * who
end
function greet(::Val{Goodbye}, who)
    return "Goodbye " * who
end
@instancedispatch greet(::GreetEnum, who) begin
    lowercase(who) == "elon" && error("We don't speak to you.")
end

```

Which would generate a function equivalent to:

```julia-auto
function greet(e::GreetEnum, who)
    lowercase(who) == "elon" && error("We don't speak to you.")
    if e == Hello
        return greet(Val(Hello), who)
    else
        return greet(Val(Goodbye), who)
    end 
end

```

Which I have found to be useful in parsing contexts where you want to quickly perform some sanity checks before handling the task to a more specialized bit of code.

Until next time!
