# Awkward case with multiple-dispatch and type heirachy

**URL:** https://discourse.julialang.org/t/awkward-case-with-multiple-dispatch-and-type-heirachy/127606
**Category:** New to Julia
**Created:** [April 1, 2025, 7:34pm UTC](https://discourse.julialang.org/t/awkward-case-with-multiple-dispatch-and-type-heirachy/127606 "2025-04-01T19:34:08Z")
**Posts on this page:** 6
**Page:** 1

<div class="post-metadata">

### Author: ![LEXUGE](https://avatars.discourse-cdn.com/v4/letter/l/53a042/32.png) [@LEXUGE](https://discourse.julialang.org/u/LEXUGE)
#### Post date: [April 1, 2025, 7:34pm UTC](https://discourse.julialang.org/t/awkward-case-with-multiple-dispatch-and-type-heirachy/127606/1 "2025-04-01T19:34:08Z")

</div>

> Some disclaimer: I am still learning Julia and I think it’s natural for me to compare it with a language I am fluent in – Rust. But I am not here arguing Rust is better than Julia or vice versa. I am totally happy and open to learning different paradigm.

I have been recently writing julia code and got into an awkward situation. I have a function `f` that has a fallback logic

```julia
function f(foo)
   # fallback logic
end

```

And I want to handle a special case for `AbstractVector{<:Integer}`. So I have

```julia
function f(foo::AbstractVector{<:Integer})
   # special case logic
end

```

However, the catch is [`Bool <: Integer`](https://github.com/JuliaLang/julia/issues/19168), and so `AbstractVector{Bool} <: AbstractVector{<:Integer}`.

And because of the type invariance, I also cannot write `AbstractVector{Integer}` as `AbstractVector{Int64}` is not a subtype of it.

However, what I really want to do is to handle a special case for “vector of integer”. So to stop `Bool` from going into these special logic I have to duplicate the fallback logic for `AbstractVector{Bool}`. This is quite awkward to me.

* * *

So my questions are:

1. What’s the best practice in this situation. **Additionally, to avoid these situations, it seems like I have to know the type hierarchy very well. How to watch out for all these special cases?**
2. I understand `true + 3 ==4` might be handy as are many cases detailed in the issue above. But I feel this case is not strong enough to make `Bool` _always_ a subtype of `Integer`. In Rust, one can handle such situation by implementing an `Add<Rhs = bool>` trait for `i32` for example. And this is essentially orthogonal to the rest of the code, i.e. in other cases, Bool and integer are quite independent from each other. My current understanding makes me feel Julia’s type hierarchy doesn’t have enough granularity that it should have.

---

<div class="post-metadata">

### Author: ![JonasWickman](https://avatars.discourse-cdn.com/v4/letter/j/9de0a6/32.png) [@JonasWickman](https://discourse.julialang.org/u/JonasWickman)
#### Post date: [April 1, 2025, 8:06pm UTC](https://discourse.julialang.org/t/awkward-case-with-multiple-dispatch-and-type-heirachy/127606/2 "2025-04-01T20:06:06Z")

</div>

There are probably more elegant solutions, but to address the specific problem of code duplication, you could define:

```julia
_f(foo) = # fallback logic
f(foo) = _f(foo)
f(foo::AbstractVector{Bool}) = _f(foo)
f(foo::AbstractVector{<:Integer}) = # My specialized case

```

---

<div class="post-metadata">

### Author: ![raminammour](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raminammour/32/13572_2.png) [@raminammour](https://discourse.julialang.org/u/raminammour)
#### Post date: [April 1, 2025, 8:06pm UTC](https://discourse.julialang.org/t/awkward-case-with-multiple-dispatch-and-type-heirachy/127606/3 "2025-04-01T20:06:17Z")

</div>

> [@LEXUGE](#):
>
> Additionally, to avoid these situations, it seems like I have to know the type hierarchy very well. How to watch out for all these special cases?

The function `subtypes` may be helpful here 🙂

---

<div class="post-metadata">

### Author: ![bertschi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bertschi/32/33462_2.png) [@bertschi](https://discourse.julialang.org/u/bertschi)
#### Post date: [April 1, 2025, 8:32pm UTC](https://discourse.julialang.org/t/awkward-case-with-multiple-dispatch-and-type-heirachy/127606/4 "2025-04-01T20:32:18Z")

</div>

The type hierarchy in Julia is a tree. If you need some other division or want to step out of the hierarchy, you can use the Holy trait pattern:

```julia
struct Default end
struct Special end

f(foo) = _f(foo, traitof(foo))

traitof(x) = Default()
traitof(x::AbstractVector{T}) where {T<:Integer} = if T == Bool; Default() else Special() end

_f(foo, ::Default) = :fallback_logic
_f(foo, ::Special) = :special_logic

```

This actually quite similar to how types can be assigned to traits in Rust, but more flexible in that it readily works with multiple dispatch.

---

<div class="post-metadata">

### Author: ![sgaure](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sgaure/32/14779_2.png) [@sgaure](https://discourse.julialang.org/u/sgaure)
#### Post date: [April 1, 2025, 9:34pm UTC](https://discourse.julialang.org/t/awkward-case-with-multiple-dispatch-and-type-heirachy/127606/5 "2025-04-01T21:34:50Z")

</div>

> [@LEXUGE](#):
>
> Additionally, to avoid these situations, it seems like I have to know the type hierarchy very well. How to watch out for all these special cases?

That’s not easy, since it’s possible to add new types to the hierarchy. Someone might e.g. define a `ModularInteger{n} <: Integer` and try to use your function. It may or may not work. If your function is only intended for “system” integer types, you can do somthing like this:

```julia
foo(x) = #fallback
const MyInteger = Union{Signed, Unsigned}
foo(x::AbstractVector{<:MyInteger}) = # the real code

```

---

<div class="post-metadata">

### Author: ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)
#### Post date: [April 1, 2025, 9:36pm UTC](https://discourse.julialang.org/t/awkward-case-with-multiple-dispatch-and-type-heirachy/127606/6 "2025-04-01T21:36:23Z")

</div>

You’re not alone, this was discussed pre-v1 and people have been occasionally making booleans less like integers ever since:  
[Introduce `UInt1` type to replace misuse of `Bool` · Issue #18367 · JuliaLang/julia](https://github.com/JuliaLang/julia/issues/18367)

The typical ways to handle this has been discussed already, and the only thing I can think to contribute is that if you don’t feel like moving logic to an internal helper method, you can use `invoke` for this purpose. It’s vulnerable to the fallback method being replaced by more specific methods though, so maybe that’s why it’s not used as much.
