# Dispatch function based on value of parametric type

**URL:** https://discourse.julialang.org/t/dispatch-function-based-on-value-of-parametric-type/9177
**Category:** General Usage
**Tags:** parametric-types
**Created:** [February 19, 2018, 8:32pm UTC](https://discourse.julialang.org/t/dispatch-function-based-on-value-of-parametric-type/9177 "2018-02-19T20:32:49Z")
**Posts on this page:** 12
**Page:** 1

<div class="post-metadata">

### Author: ![RandomString123](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/randomstring123/32/3194_2.png) [@RandomString123](https://discourse.julialang.org/u/RandomString123)
#### Post date: [February 19, 2018, 8:32pm UTC](https://discourse.julialang.org/t/dispatch-function-based-on-value-of-parametric-type/9177/1 "2018-02-19T20:32:49Z")

</div>

I have been thinking about parametric types lately and how to use them so I came up with a thought experiment that I can’t seem to figure out, but I am pretty sure is possible. For this experiment lets assume there is a boolean associated with a type. There are two method routes for this type one to be taken one if the boolean is true, and one to be taken if it is false.

I could see this as an alternative to a situation where you have a base type and then two subtypes one that signals a condition is true and one that signals an alternate condition. And where the only difference between the subtypes is the presence or absence of this condition. In essence I want to implement this functionality only by storing the boolean as a parametric and not a field. This code shows the non-parametric way of doing this:

```julia
struct WorkingType{T}
    B::Bool
    s::T
end

w = WorkingType(true, 10) # true condition
w2 = WorkingType(false, 10) # false condition
testval(w) = w.B ? print(w.s) : print(-1 * w.s)

testval(w) # 10
testval(w2) # -10

```

Now lets assume i still want to store s in a field but have its type as a parametric so it can support a variety of types and I just want Julia to dispatch to the correct function based on the (Boolean) parametric being true or false. Here is an outline of what I think needs to happen with ??? where I am unsure of the syntax.

```julia
struct BustedType{B, T}
    s::T
end

t = BustedType{???}(???) # true condition
t2 = BustedType{???}(???) # false condition

testval(::BustedType{???}) = print(???) # 10
testval(::BustedType{???}) = print(-1 * ???) # -10

```

Bonus question: Would it be possible to do the above except store both S and B as parametric values and then switch on three conditions ex:

- s \< 10 && b is true = print 1
- s \>= 10 && b is true = print 1 \* s
- s is false = print -1 \* s

---

<div class="post-metadata">

### Author: ![mohamed82008](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mohamed82008/32/18171_2.png) [@mohamed82008](https://discourse.julialang.org/u/mohamed82008)
#### Post date: [February 19, 2018, 9:57pm UTC](https://discourse.julialang.org/t/dispatch-function-based-on-value-of-parametric-type/9177/2 "2018-02-19T21:57:23Z")

</div>

```julia
julia> struct BustedType{B, T}
           s::T
       end

julia> BustedType{B}(s::T) where {B,T} = BustedType{B,T}(s)

julia> t = BustedType{true}(10)
BustedType{true,Int64}(10)

julia> t2 = BustedType{false}(10)
BustedType{false,Int64}(10)

julia> testval(w::BustedType{true}) = print(w.s)
testval (generic function with 1 method)

julia> testval(w::BustedType{false}) = print(-1 * w.s)
testval (generic function with 2 methods)

julia> testval(t)
10
julia> testval(t2)
-10
julia> @which testval(t)
testval(w::BustedType{true,T} where T) in Main at REPL[5]:1

julia> @which testval(t2)
testval(w::BustedType{false,T} where T) in Main at REPL[6]:1

julia> struct BustedType2{B, s} end

julia> t = BustedType2{true,10}()
BustedType2{true,10}()

julia> t2 = BustedType2{false,10}()
BustedType2{false,10}()

julia> @generated function testval(::BustedType2{B,s}) where {B, s}
           if s < 10 && B
               return :(print(1))
           elseif s >= 10 && B
               return :(print(s))
           else
               return :(print(-s))
           end
       end
testval (generic function with 3 methods)

julia> testval(t)
10
julia> testval(t2)
-10

```

Note that when you make some field a type parameter, you can no longer enforce its type to be a subtype of `Integer` for example so nothing stops you from making a `BustedType2{"A", "B"}` which will error if comparing `"B" < 10`.

---

<div class="post-metadata">

### Author: ![dpsanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dpsanders/32/3573_2.png) [@dpsanders](https://discourse.julialang.org/u/dpsanders)
#### Post date: [February 19, 2018, 10:34pm UTC](https://discourse.julialang.org/t/dispatch-function-based-on-value-of-parametric-type/9177/3 "2018-02-19T22:34:00Z")

</div>

Just put T \<: Integer in the type parameter list?

---

<div class="post-metadata">

### Author: ![mohamed82008](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mohamed82008/32/18171_2.png) [@mohamed82008](https://discourse.julialang.org/u/mohamed82008)
#### Post date: [February 19, 2018, 11:47pm UTC](https://discourse.julialang.org/t/dispatch-function-based-on-value-of-parametric-type/9177/4 "2018-02-19T23:47:01Z")

</div>

No, because it seems the OP wants `true` and `10` to be in the parameters, so these are not types anymore and `<: Integer` only works if the parameter is a type, not an object with type `<: Integer`.

---

<div class="post-metadata">

### Author: ![dpsanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dpsanders/32/3573_2.png) [@dpsanders](https://discourse.julialang.org/u/dpsanders)
#### Post date: [February 20, 2018, 12:25am UTC](https://discourse.julialang.org/t/dispatch-function-based-on-value-of-parametric-type/9177/5 "2018-02-20T00:25:02Z")

</div>

Thanks, I had misunderstood.

---

<div class="post-metadata">

### Author: ![RandomString123](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/randomstring123/32/3194_2.png) [@RandomString123](https://discourse.julialang.org/u/RandomString123)
#### Post date: [February 20, 2018, 1:29am UTC](https://discourse.julialang.org/t/dispatch-function-based-on-value-of-parametric-type/9177/6 "2018-02-20T01:29:13Z")

</div>

The solution is much simper than I thought thanks! The documentation I was looking at must have been old. It had examples with Val{} in it which just seemed…weird.

One question. When you define the method `testval(w::BustedType{true}) = print(w.s)` you only use `w::BustedType{true}` even though the actual type is `BustedType{true, T}` as is seen on the @which lines. Can the unimportant (for dispatch) parameters typically be discarded? Or was this just a unique case?

---

<div class="post-metadata">

### Author: ![Ralph\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ralph_smith/32/10344_2.png) [@Ralph\_Smith](https://discourse.julialang.org/u/Ralph_Smith)
#### Post date: [February 20, 2018, 3:00am UTC](https://discourse.julialang.org/t/dispatch-function-based-on-value-of-parametric-type/9177/7 "2018-02-20T03:00:41Z")

</div>

> [@mohamed82008](#):
>
> Note that when you make some field a type parameter, you can no longer enforce its type to be a subtype of Integer for example

You could validate in an inner constructor:

```julia
struct BustedType2{B,S}
    function BustedType2{B,S}() where {B,S}
        (isa(B,Bool) && isa(S,Integer)) || error("bad params")
        new()
    end
end

```

---

<div class="post-metadata">

### Author: ![mohamed82008](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mohamed82008/32/18171_2.png) [@mohamed82008](https://discourse.julialang.org/u/mohamed82008)
#### Post date: [February 20, 2018, 4:04am UTC](https://discourse.julialang.org/t/dispatch-function-based-on-value-of-parametric-type/9177/8 "2018-02-20T04:04:59Z")

</div>

> [@RandomString123](#):
>
> Can the unimportant (for dispatch) parameters typically be discarded? Or was this just a unique case?

Well, `BustedType{true}` is an alias for `BustedType{true, T} where T`. In one layered parameterization, you can drop the unused parameters from the end without a problem. But you cannot drop the first parameter only for example without aliasing the type. For example, you can do `const InvertedBustedType{T,B} = BustedType{B,T}` then you can drop `B` if you want using `InvertedBustedType{T}` which is now an alias of `BustedType{B,T} where B`.

For deeper parameterizations, it’s best to use all parameters (unless you are dealing with tuples or dropping parameters at the shallowest level). A rule of thumb is to check that every possible valid argument `arg` passes the `arg isa T` test, where the function signature is `f(arg::T)`. One problem you may run into when omitting parameters is this:

```julia
julia> a = [1,2,3];

julia> a isa Array{Int}
true

julia> a isa Array{Int, 1}
true

julia> a = [[1,2,3], [1,2,3], [1,2,3]];

julia> a isa Array{Array{Int}, 1}
false

julia> a isa Array{Array{Int, 1}, 1}
true

julia> a[1] isa Array{Int}
true

```

Omitting the parameter from the inner `Array{Int, 1}` led to an undesired behavior because `a` does not pass the `arg isa T` test anymore, even though `a[1] isa Array{Int}` is true. This is the infamous type invariance issue of Julia types, see [https://docs.julialang.org/en/stable/manual/types/#Parametric-Composite-Types-1](https://docs.julialang.org/en/stable/manual/types/#Parametric-Composite-Types-1). Tuples are an exception in that `isa` can “see through” a tuple, so a tuple layer doesn’t cause the same problem an array or any other layer would.

```julia
julia> a = ([1,2,3], [1,2,3], [1,2,3]);

julia> a isa NTuple{3, Array{Int}}
true

julia> a isa NTuple{3, Array{Int, 1}}
true

```

---

<div class="post-metadata">

### Author: ![RandomString123](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/randomstring123/32/3194_2.png) [@RandomString123](https://discourse.julialang.org/u/RandomString123)
#### Post date: [February 20, 2018, 3:24pm UTC](https://discourse.julialang.org/t/dispatch-function-based-on-value-of-parametric-type/9177/9 "2018-02-20T15:24:44Z")

</div>

One last question on the subject that I don’t see in the parametric types docs.

Is there an easy way to manipulate the parameters stored in a type? For example, turn `BustedType2{true,10}()` into `BustedType2{false,10}()` by just flipping the true to a false? I would like to do this without having to re-create a whole new type.

---

<div class="post-metadata">

### Author: ![dpsanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dpsanders/32/3573_2.png) [@dpsanders](https://discourse.julialang.org/u/dpsanders)
#### Post date: [February 20, 2018, 11:42pm UTC](https://discourse.julialang.org/t/dispatch-function-based-on-value-of-parametric-type/9177/10 "2018-02-20T23:42:46Z")

</div>

Why are trying to do this using type parameters, instead of just making a new type with these variables inside?

---

<div class="post-metadata">

### Author: ![mohamed82008](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mohamed82008/32/18171_2.png) [@mohamed82008](https://discourse.julialang.org/u/mohamed82008)
#### Post date: [February 21, 2018, 1:52am UTC](https://discourse.julialang.org/t/dispatch-function-based-on-value-of-parametric-type/9177/11 "2018-02-21T01:52:19Z")

</div>

> [@RandomString123](#):
>
> Is there an easy way to manipulate the parameters stored in a type?

Manipulating is not possible as far as I know. Making a new instance with the Boolean flipped, that’s possible but if you assign it to the same variable, that’s type instability, because you would have changed the type of the variable. Making a new instance and assigning it to a different variable is the healthiest option:

```julia
julia> struct BustedType2{B,S} end

julia> flipped(::BustedType2{B,S}) where {B,S} = BustedType2{!B,S}()
flipped (generic function with 1 method)

julia> t = BustedType2{true,10}()
BustedType2{true,10}()

julia> t2 = flipped(t)
BustedType2{false,10}()

```

And resonating David’s question, it’s unlikely you really need this. If you need to change `B` often, then make it a field in a `mutable struct`.

---

<div class="post-metadata">

### Author: ![RandomString123](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/randomstring123/32/3194_2.png) [@RandomString123](https://discourse.julialang.org/u/RandomString123)
#### Post date: [February 21, 2018, 4:43pm UTC](https://discourse.julialang.org/t/dispatch-function-based-on-value-of-parametric-type/9177/12 "2018-02-21T16:43:27Z")

</div>

Nothing in particular. It is a thought / simple code experiment to understand how parameterized types work and their limitations.
