# Multiple dispatch: Value and type methods

**URL:** <https://discourse.julialang.org/t/multiple-dispatch-value-and-type-methods/72901>\
**Category:** General Usage\
**Tags:** question\
**Created:** [December 10, 2021, 4:16pm UTC](https://discourse.julialang.org/t/multiple-dispatch-value-and-type-methods/72901 "2021-12-10T16:16:20Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![cscherrer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cscherrer/32/7631_2.png) [@cscherrer](https://discourse.julialang.org/u/cscherrer)\
**Post date:** [December 10, 2021, 4:16pm UTC](https://discourse.julialang.org/t/multiple-dispatch-value-and-type-methods/72901/1 "2021-12-10T16:16:20Z")

</div>

I’ve found it very handy to sometimes define things like

```julia
foo(x::T) = foo(T)

function foo(::Type{T}) where {T}
    ...
end

```

I’ve heard suggestions that this is bad style, but to me it seems like a useful idiom for cases where a function depends only on the type of its argument.

Am I missing something?

---

<div class="post-metadata">

**Author:** ![jw3126](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jw3126/32/3086_2.png) [@jw3126](https://discourse.julialang.org/u/jw3126)\
**Post date:** [December 10, 2021, 4:28pm UTC](https://discourse.julialang.org/t/multiple-dispatch-value-and-type-methods/72901/2 "2021-12-10T16:28:48Z")

</div>

I also find it useful, especially for traits and it is also used in `Base` quite a bit. (`eltype`, `Base.IndexStyle`, …).

In julia 1.7 this pattern is bad for inference when combined with recursion however  
[https://github.com/JuliaLang/julia/issues/43296#issuecomment-991104427](https://github.com/JuliaLang/julia/issues/43296#issuecomment-991104427)

---

<div class="post-metadata">

**Author:** ![cscherrer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cscherrer/32/7631_2.png) [@cscherrer](https://discourse.julialang.org/u/cscherrer)\
**Post date:** [December 10, 2021, 5:18pm UTC](https://discourse.julialang.org/t/multiple-dispatch-value-and-type-methods/72901/3 "2021-12-10T17:18:43Z")

</div>

Interesting, I had something similar, with

```julia
function basemeasure_depth(μ::M) where {M}
    basemeasure_depth(M)
end

```

I was getting

```julia
julia> @inferred basemeasure_depth(Normal())
ERROR: return type Static.StaticInt{3} does not match inferred return type Any
Stacktrace:
 [1] error(s::String)
   @ Base ./error.jl:33
 [2] top-level scope
   @ REPL[118]:1

```

But the fix was easy:

```julia
@generated function basemeasure_depth(μ::M) where {M}
    basemeasure_depth(M)
end

```

So now it’s

```julia
julia> @inferred basemeasure_depth(Normal())
static(3)

```

This is a type-level recursion – some types have `basemeasure_depth(::Type{T}) == static(0)`, and the rest count the number of simplifications steps they take to get to this. Maybe something similar could work for your case?

---

<div class="post-metadata">

**Author:** ![jzr](https://avatars.discourse-cdn.com/v4/letter/j/eb9ed0/32.png) [@jzr](https://discourse.julialang.org/u/jzr)\
**Post date:** [December 10, 2021, 6:38pm UTC](https://discourse.julialang.org/t/multiple-dispatch-value-and-type-methods/72901/4 "2021-12-10T18:38:32Z")

</div>

This pattern mixes the value level with the type level. There are valid cases for that, but I see it as a very specific style of programming. If I don’t especially need to combine them, I would give the type method a different name from the value method. Otherwise the semantics of the function become unclear. If it is simply a convenience API so users can pass “an instance or its type”, I think that’s just bad design. A function should have a clear and simple API. Converting non-equivalent objects into one another is a mess.

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [December 10, 2021, 6:44pm UTC](https://discourse.julialang.org/t/multiple-dispatch-value-and-type-methods/72901/5 "2021-12-10T18:44:25Z")

</div>

classic example of this doesn’t make sense:

```julia
julia> zero(1)
0

julia> zero(Int)
0

julia> zero([1])
1-element Vector{Int64}:
 0

julia> zero(Vector{Int64})
ERROR: MethodError: no meth

```

---

<div class="post-metadata">

**Author:** ![cscherrer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cscherrer/32/7631_2.png) [@cscherrer](https://discourse.julialang.org/u/cscherrer)\
**Post date:** [December 10, 2021, 7:13pm UTC](https://discourse.julialang.org/t/multiple-dispatch-value-and-type-methods/72901/6 "2021-12-10T19:13:51Z")

</div>

> [@jzr](#):
>
> If I don’t especially need to combine them, I would give the type method a different name from the value method. Otherwise the semantics of the function become unclear. If it is simply a convenience API so users can pass “an instance or its type”, I think that’s just bad design.

There’s never a _need_, more that it gets annoying to have different names for things that are conceptually the same. Of course it’s a bad idea to do this in cases where the semantics are unclear. But most programming idioms have exceptions; that doesn’t mean it’s universally a bad idiom.

> [@jzr](#):
>
> A function should have a clear and simple API.

I agree; in cases where I’d use this approach, it’s in part to make the API more clear and simple.

> [@jzr](#):
>
> Converting non-equivalent objects into one another is a mess.

I don’t understand this at all. Lossily converting between inequivalent forms is the whole point of functions, which we use all over the place.

> [@jling](#):
>
> classic example of this doesn’t make sense:

Sure, and there are plenty more. But there are also plenty of examples where the result of a function depends only on the type of the argument, and more importantly, where it makes semantic sense to consider something as a function of the type. In those cases, I don’t see a danger of adding a convenience function to forward calls on non-types to the type methods.

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [December 10, 2021, 7:34pm UTC](https://discourse.julialang.org/t/multiple-dispatch-value-and-type-methods/72901/7 "2021-12-10T19:34:52Z")

</div>

> [@cscherrer](#):
>
> I don’t see a danger of adding a convenience function

absolutely agree 😉

---

<div class="post-metadata">

**Author:** ![jzr](https://avatars.discourse-cdn.com/v4/letter/j/eb9ed0/32.png) [@jzr](https://discourse.julialang.org/u/jzr)\
**Post date:** [December 10, 2021, 7:44pm UTC](https://discourse.julialang.org/t/multiple-dispatch-value-and-type-methods/72901/8 "2021-12-10T19:44:46Z")

</div>

> [@cscherrer](#):
>
> > [@jzr](#):
> >
> > Converting non-equivalent objects into one another is a mess.
> 
> I don’t understand this at all. Lossily converting between inequivalent forms is the whole point of functions, which we use all over the place.

Two objects of different types can be equivalent under some particular relation. For example, an Int32 and Int64 aren’t generically equivalent, but it’s no trouble to evaluate `>(0::Int64)(x)` by first converting `x::Int32` to `Int64`. No problem there.

Could you give an example of some basic function where treating an object and its type both as valid inputs would make sense? Why not just pass the type if I only need the type? Or, why not just distingush between the two functions? For example,

```julia
handlevalue(x::T) = handletype(T)
handletype(T::Type{T}) = 123

```

Note these are different functions, not a mixture of two functions into one. If I mixed them into one function, I can’t easily describe what that function means.

The only application I know of that treats `42` and `Int` the same is in constraint lattice programming, where one restricts value a value `x` by declaring sets into which it must fall, such as `x = int; x < 4; x = {2, 9}`. But in this style, the value of `x` is actually not a number, but a set of numbers, which the program may convert from a singleton set into a number at the end of the process to select a satisfying value.

---

<div class="post-metadata">

**Author:** ![CameronBieganek](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cameronbieganek/32/6915_2.png) [@CameronBieganek](https://discourse.julialang.org/u/CameronBieganek)\
**Post date:** [December 10, 2021, 7:59pm UTC](https://discourse.julialang.org/t/multiple-dispatch-value-and-type-methods/72901/9 "2021-12-10T19:59:24Z")

</div>

> [@jzr](#):
>
> Could you give an example of some basic function where treating an object and its type both as valid inputs would make sense?

It’s common in Base to provide convenience methods for trait functions of the type described by OP.

> <https://github.com/JuliaLang/julia/blob/3bf9d1773144bc4943232dc2ffaac307a700853d/base/abstractarray.jl#L206>

> <https://github.com/JuliaLang/julia/blob/3bf9d1773144bc4943232dc2ffaac307a700853d/base/indices.jl#L94>

> <https://github.com/JuliaLang/julia/blob/3bf9d1773144bc4943232dc2ffaac307a700853d/base/generator.jl#L91>

> <https://github.com/JuliaLang/julia/blob/3bf9d1773144bc4943232dc2ffaac307a700853d/base/generator.jl#L125>

---

<div class="post-metadata">

**Author:** ![jzr](https://avatars.discourse-cdn.com/v4/letter/j/eb9ed0/32.png) [@jzr](https://discourse.julialang.org/u/jzr)\
**Post date:** [December 10, 2021, 8:16pm UTC](https://discourse.julialang.org/t/multiple-dispatch-value-and-type-methods/72901/10 "2021-12-10T20:16:08Z")

</div>

I know some people have written functions this way, but I don’t see what it buys them. What’s wrong with different functions for different jobs?

```julia
valeltype(x) = eltype(typeof(x))
eltype(::Type{<:AbstractArray{E}}) where {E} = @isdefined(E) ? E : Any

```

Otherwise it feels like we’re back in numpy with automatic broadcasting where it’s unclear whether a call is lifted or not (a different lift in this case, but the same idea). In Julia we have a simpler semantics, and I think that’s good. In some functions here and there, Julia [slips up and automatically lifts](https://github.com/JuliaLang/julia/issues/34395), but I don’t think we need more of that.

I like the distinction between “simple” and “easy” made in [Rich Hickey’s famous talk “Simple Made Easy”](https://www.youtube.com/watch?v=LKtk3HCgTa8).

---

<div class="post-metadata">

**Author:** ![CameronBieganek](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cameronbieganek/32/6915_2.png) [@CameronBieganek](https://discourse.julialang.org/u/CameronBieganek)\
**Post date:** [December 10, 2021, 8:45pm UTC](https://discourse.julialang.org/t/multiple-dispatch-value-and-type-methods/72901/11 "2021-12-10T20:45:06Z")

</div>

> [@jzr](#):
>
> different functions for different jobs

If we followed that dictum, we wouldn’t be able to use duck typing or multiple dispatch anymore. Every method of a generic function is a “different function for a different job”. I’d hate to have to write code like this:

```julia
foo_int(x::Int) = 1
foo_float(x::Float64) = 2
foo_string(x::String) = 3

```

I think the `eltype(x) = eltype(typeof(x))` method is a perfectly reasonable behavior for the generic `eltype` function applied to an object.

---

<div class="post-metadata">

**Author:** ![cscherrer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cscherrer/32/7631_2.png) [@cscherrer](https://discourse.julialang.org/u/cscherrer)\
**Post date:** [December 10, 2021, 8:56pm UTC](https://discourse.julialang.org/t/multiple-dispatch-value-and-type-methods/72901/12 "2021-12-10T20:56:25Z")

</div>

> [@jzr](#):
>
> Could you give an example of some basic function where treating an object and its type both as valid inputs would make sense?

In MeasureTheory.jl, we have lots of cases where one measure is defined in terms of another, so `logdensity_def(m, x)` gives the log-density with respect to `basemeasure(m)`. But then we often want the density with respect to the “root measure”, which you can get by iterating `basemeasure` to a fix point.

Doing this dynamically is expensive, so I’ve added a `basemeasure_depth` that returns a `StaticInt` of the number of iterations to get to that fixpoint. It needs to be static, so we usually want to jump to the type level ASAP. These are conceptually close enough that having one name is just more convenient.

There is a potential problem though - if you define

```julia
basemeasure_depth(m::M) = basemeasure_depth(M)

```

it’s easy to accidentally end up forcing the compiler into an infinite recursion. The stack overflow is uglier than one you’d get at the value level, because it takes longer for it to figure out why it’s stuck.

---

<div class="post-metadata">

**Author:** ![jzr](https://avatars.discourse-cdn.com/v4/letter/j/eb9ed0/32.png) [@jzr](https://discourse.julialang.org/u/jzr)\
**Post date:** [December 10, 2021, 9:01pm UTC](https://discourse.julialang.org/t/multiple-dispatch-value-and-type-methods/72901/13 "2021-12-10T21:01:41Z")

</div>

> [@CameronBieganek](#):
>
> If we followed that dictum, we wouldn’t be able to use duck typing or multiple dispatch anymore. Every method of a generic function is a “different function for a different job”.

The one job of a generic function can be abstract but it should have a shared functional specification. `Base.+` is _addition_. It has a coherent definition that is polymorphic across data types with a shared specification for types that form an algebraic structure having associativity, commutativity, and identity.

---

<div class="post-metadata">

**Author:** ![jzr](https://avatars.discourse-cdn.com/v4/letter/j/eb9ed0/32.png) [@jzr](https://discourse.julialang.org/u/jzr)\
**Post date:** [December 10, 2021, 9:14pm UTC](https://discourse.julialang.org/t/multiple-dispatch-value-and-type-methods/72901/14 "2021-12-10T21:14:12Z")

</div>

> [@cscherrer](#):
>
> These are conceptually close enough that having one name is just more convenient.

In this case I would rename one of them:

```julia
tbasemeasure_depth(::Type{M}) = ...
basemeasure_depth(m::M) = tbasemeasure_depth(M)

```

or

```julia
basemeasure_depth(::Type{M}) = ...
vbasemeasure_depth(m::M) = basemeasure_depth(M)

```

---

<div class="post-metadata">

**Author:** ![CameronBieganek](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cameronbieganek/32/6915_2.png) [@CameronBieganek](https://discourse.julialang.org/u/CameronBieganek)\
**Post date:** [December 10, 2021, 9:19pm UTC](https://discourse.julialang.org/t/multiple-dispatch-value-and-type-methods/72901/15 "2021-12-10T21:19:48Z")

</div>

> [@jzr](#):
>
> It has a coherent definition that is polymorphic across data types

It sounds like you’re limiting yourself to parametric polymorphism. What about ad hoc polymorphism? What counts as a “coherent definition”? I can be as vague as I want to with the definition of my generic functions. I could write a package like this:

```julia
"""
foo(args...; kwargs...)

Do something.
"""
function foo end

# Every function in my package is a method of `foo`.

```

In other words, it’s a bit subjective how we decide to partition the space of functions into “methods of `bar`” and “not methods of `bar`”.
