# Dispatch on singleton type inside a tuple

**URL:** https://discourse.julialang.org/t/dispatch-on-singleton-type-inside-a-tuple/3058
**Category:** General Usage
**Tags:** question, inference
**Created:** [April 5, 2017, 10:29am UTC](https://discourse.julialang.org/t/dispatch-on-singleton-type-inside-a-tuple/3058 "2017-04-05T10:29:21Z")
**Posts on this page:** 9
**Page:** 1

<div class="post-metadata">

### Author: ![traktofon](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/traktofon/32/591_2.png) [@traktofon](https://discourse.julialang.org/u/traktofon)
#### Post date: [April 5, 2017, 10:29am UTC](https://discourse.julialang.org/t/dispatch-on-singleton-type-inside-a-tuple/3058/1 "2017-04-05T10:29:21Z")

</div>

Hello,

in order to dispatch on a datatype known at runtime, we can use singleton types:

```julia
func1(::Type{T},n) where T = Array{T}(n)

```

which seems to give a type-stable result:

```julia
julia> @code_warntype func1(Int32,10)
Variables:
  #self#::#func1
  #unused#::Any
  n::Int64

Body:
  begin 
      return $(Expr(:foreigncall, :(:jl_alloc_array_1d), Array{Int32,1}, svec(Any, Int64), Array{Int32,1}, 0, :(n), 0))
  end::Array{Int32,1}

```

Here the return type is inferred correctly. I believe the `#unused#::Any` is not a problem, though I’m not sure.

I wonder how I can achieve the same type-stable behavior if my `func` function doesn’t take the datatype and integer parameters separately, but combined in a tuple. (The eventually intended function should take a variable number of such tuples.) My first try:

```julia
func2(spec::Tuple{Type{T},Int}) where T = Array{T}(spec[2])

```

doesn’t work:

```julia
julia> func2((Int32,10))
ERROR: MethodError: no method matching func2(::Tuple{DataType,Int64})

```

seemingly because the type of `(Int32,10)` is `Tuple{DataType,Int64}`, not `Tuple{Type{Int32},Int64}`. But if I define my `func` accordingly,

```julia
func3(spec::Tuple{DataType,Int}) = Array{spec[1]}(spec[2])

```

then the return type can no longer be inferred:

```julia
julia> @code_warntype func3((Int32,10))
Variables:
  #self#::#func3
  spec::Tuple{DataType,Int64}

Body:
  begin 
      return ((Core.apply_type)(Main.Array, (Base.getfield)(spec::Tuple{DataType,Int64}, 1)::DataType)::Type{Array{_,N} where N} where _)((Base.getfield)(spec::Tuple{DataType,Int64}, 2)::Int64)::Array{_,1} where _
  end::Array{_,1} where _ # inferred return type is not concrete!

```

Adding a function barrier, i.e.

```julia
function func4(spec::Tuple{DataType,Int}); T,n=spec; func1(T,n); end

```

also doesn’t help.

Is it possible to properly dispatch on the singleton type inside the tuple? How? Thanks.

---

<div class="post-metadata">

### Author: ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)
#### Post date: [April 5, 2017, 12:23pm UTC](https://discourse.julialang.org/t/dispatch-on-singleton-type-inside-a-tuple/3058/2 "2017-04-05T12:23:27Z")

</div>

See Trick 1 here:  
[https://github.com/stevengj/18S096-iap17/tree/master/lecture3](https://github.com/stevengj/18S096-iap17/tree/master/lecture3)

---

<div class="post-metadata">

### Author: ![cstjean](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cstjean/32/1444_2.png) [@cstjean](https://discourse.julialang.org/u/cstjean)
#### Post date: [April 5, 2017, 11:26pm UTC](https://discourse.julialang.org/t/dispatch-on-singleton-type-inside-a-tuple/3058/3 "2017-04-05T23:26:13Z")

</div>

It’s related to [this issue](https://github.com/JuliaLang/julia/issues/10947). I haven’t found a clean solution, but wrapping the type in `Val` “solves” the problem.

```julia
julia> func5{T}(spec::Tuple{Val{T}, Int}) = Vector{T}(spec[2])
func5 (generic function with 1 method)

julia> func5((Val{Int32}(), 10)) # type-stable

```

---

<div class="post-metadata">

### Author: ![traktofon](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/traktofon/32/591_2.png) [@traktofon](https://discourse.julialang.org/u/traktofon)
#### Post date: [April 6, 2017, 2:49am UTC](https://discourse.julialang.org/t/dispatch-on-singleton-type-inside-a-tuple/3058/5 "2017-04-06T02:49:01Z")

</div>

Thanks, @Tamas_Papp. But I’m afraid this trick doesn’t work for the case of having types inside the tuple. If I understand correctly, what I should do according to the trick is:

```julia
# func1 corresponds to "argtail" in stevengj's notebook
func1(::Type{T}, dims...) where T = Array{T}(dims...)
# func2 corresponds to "tupletail"
func2(spec) = func1(spec...)

```

With this, the return-type inference works for func1:

```julia
@code_warntype func1(Int32,10)
Variables:
  #self#::#func1
  #unused#::Any
  dims::Tuple{Int64}

Body:
  begin 
      return $(Expr(:foreigncall, :(:jl_alloc_array_1d), Array{Int32,1}, svec(Any, Int64), Array{Int32,1}, 0, :((Core.getfield)(dims, 1)::Int64), 0))
  end::Array{Int32,1}

```

but not for func2:

```julia
Variables:
  #self#::#func2
  spec::Tuple{DataType,Int64}

Body:
  begin 
      return (Main.func1)((Core.getfield)(spec::Tuple{DataType,Int64}, 1)::DataType, (Core.getfield)(spec::Tuple{DataType,Int64}, 2)::Int64)::Any
  end::Any # not even Array{_,1} !

```

It’s even worse than my original approach, as it doesn’t infer that the return type is an Array.

If I misunderstood how to apply the trick to my case, please help me get it right.

I believe the problem comes from `typeof(Int32)==DataType` instead of `typeof(Int32)==Type{Int32}`.

---

<div class="post-metadata">

### Author: ![traktofon](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/traktofon/32/591_2.png) [@traktofon](https://discourse.julialang.org/u/traktofon)
#### Post date: [April 6, 2017, 3:00am UTC](https://discourse.julialang.org/t/dispatch-on-singleton-type-inside-a-tuple/3058/6 "2017-04-06T03:00:30Z")

</div>

Thanks, @cstjean. The [issue #10947](https://github.com/JuliaLang/julia/issues/10947) is spot-on. If anyone is collecting votes for making `typeof(T)==Type{T}` (where `T isa DataType`), you’d have my vote. 🙂

The workaround of using `Val{T}` instead of `Type{T}` indeed works beautifully. Unfortunately for my intended use case, the goal is to have a convenient (i.e. as short as possible) way for the user to specify a datatype and one (or several) integers, so the `Val` approach falls short. I had hoped to achieve this without macros, but maybe it’s not possible.

---

<div class="post-metadata">

### Author: ![cstjean](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cstjean/32/1444_2.png) [@cstjean](https://discourse.julialang.org/u/cstjean)
#### Post date: [April 6, 2017, 3:31am UTC](https://discourse.julialang.org/t/dispatch-on-singleton-type-inside-a-tuple/3058/7 "2017-04-06T03:31:22Z")

</div>

> [@traktofon](#):
>
> Unfortunately for my intended use case, the goal is to have a convenient (i.e. as short as possible) way for the user to specify a datatype and one (or several) integers, so the Val approach falls short. I had hoped to achieve this without macros, but maybe it’s not possible.

You could also create a type so that the user passes `Spec{Int}(12)`.

---

<div class="post-metadata">

### Author: ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)
#### Post date: [April 6, 2017, 4:15am UTC](https://discourse.julialang.org/t/dispatch-on-singleton-type-inside-a-tuple/3058/8 "2017-04-06T04:15:08Z")

</div>

The custom type approach that @cstjean suggested is also more easily extended in the future if you decide to add, for example, a second optional argument to the `Spec` constructor.

---

<div class="post-metadata">

### Author: ![traktofon](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/traktofon/32/591_2.png) [@traktofon](https://discourse.julialang.org/u/traktofon)
#### Post date: [April 6, 2017, 9:30am UTC](https://discourse.julialang.org/t/dispatch-on-singleton-type-inside-a-tuple/3058/9 "2017-04-06T09:30:12Z")

</div>

Thanks, @cstjean and @rdeits, for the suggestion of using a dedicated type. This surely works, but it doesn’t help much, as the user already has the option to just pass `Array{T}(n)`. I just wanted a way for the user to pass `(T,n)` instead, as there are potentially many such specifications to pass. (For the record, the original problem occurs in my package [FortranFiles.jl](https://github.com/traktofon/FortranFiles.jl), and the code I’m trying to optimize is in the [read\_spec](https://github.com/traktofon/FortranFiles.jl/blob/master/src/read.jl#L56) function.)

There is actually another similar problem, which not directly involves tuples. It boils down to this:

```julia
julia> zz(xs...) = map(zero, xs)

```

If called with regular types, the return-type inference works well:

```julia
Variables:
  #self#::#zz
  xs::Tuple{Int64,Float64,UInt8}

Body:
  begin 
      return (Core.tuple)(0, (Base.sitofp)(Float64, 0)::Float64, (Base.checked_trunc_uint)(UInt8, 0)::UInt8)::Tuple{Int64,Float64,UInt8}
  end::Tuple{Int64,Float64,UInt8}

```

but if I replace one argument with a datatype, inference fails:

```julia
@code_warntype zz(Int, 1.0, 0x01)
Variables:
  #self#::#zz
  xs::Tuple{DataType,Float64,UInt8}

Body:
  begin 
      return (Core.tuple)((Main.zero)((Base.getfield)(xs::Tuple{DataType,Float64,UInt8}, 1)::DataType)::Any, (Base.sitofp)(Float64, 0)::Float64, (Base.checked_trunc_uint)(UInt8, 0)::UInt8)::Tuple{Any,Float64,UInt8}
  end::Tuple{Any,Float64,UInt8} # Any instead of Int64

```

I tried to apply @stevengj’s recursive argument processing trick which @Tamas_Papp suggested, as follows:

```julia
julia> zz() = ()
julia> zz(x, xs...) = (zero(x), zz(xs...)...)

```

The return-type is now inferred correctly if the **first** argument is a datatype:

```julia
julia> @code_warntype zz(Int, 1.0, 0x01)
Variables:
  #self#::#zz
  x::Any
  xs::Tuple{Float64,UInt8}

Body:
  begin 
      return (Core.tuple)(0, (Base.sitofp)(Float64, 0)::Float64, (Base.checked_trunc_uint)(UInt8, 0)::UInt8)::Tuple{Int64,Float64,UInt8}
  end::Tuple{Int64,Float64,UInt8} # Yay!

```

(though note the `x::Any` warning), but not if a later argument is a datatype:

```julia
julia> @code_warntype zz(1, Float64, 0x01)
Variables:
  #self#::#zz
  x::Int64
  xs::Tuple{DataType,UInt8}

Body:
  begin 
      return (Core.tuple)(0, (Main.zero)((Core.getfield)(xs::Tuple{DataType,UInt8}, 1)::DataType)::Any, (Base.checked_trunc_uint)(UInt8, 0)::UInt8)::Tuple{Int64,Any,UInt8}                                                                                                                                       
  end::Tuple{Int64,Any,UInt8} # again Any :(

```

Any advice on how to fix this is appreciated!

---

<div class="post-metadata">

### Author: ![cstjean](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cstjean/32/1444_2.png) [@cstjean](https://discourse.julialang.org/u/cstjean)
#### Post date: [April 6, 2017, 1:39pm UTC](https://discourse.julialang.org/t/dispatch-on-singleton-type-inside-a-tuple/3058/10 "2017-04-06T13:39:58Z")

</div>

Technically, you could write a macro that creates the definitions for `zz(a) = ...`, `zz(a, b) = ...`, etc. But that’s not very clean. Could you write instead a macro like this?

```julia
my_spec = @spec begin
x => (Int, Float64, 5)
y => (Float64,)
...
end

```

Then it’s easy to make type-stable.
