# Inference for tuple of callable objects

#1

I have some objects that are callable, each performing a certain univariate transformation. They are type stable; heavily simplified MWE:

``````using Base.Test

struct One end
struct Two end

(::One)(x) = x+1
(::Two)(x) = x+2

@inferred (One())(1)            # OK
@inferred (Two())(1)            # OK
``````

What I want to do is collect them to transform vectors. I am using tuples, so that I can specialize the type, however, the transformation itself is not type stable:

``````struct Many{T}
t::T
end

m = Many((One(),Two()))
(m::Many)(x) = [t(x) for (t,x) in zip(m.t, x)]
@inferred m([1,2]) # get Array{Int, 1}, infers Array{_, 1}
``````

How can I fix this?

#2

`zip` is type-unstable over heterogeneous tuples. If you don’t mind putting `x` in a tuple too, then you can use the unregistered Unrolled.jl

``````julia> using Unrolled

julia> (m::Many)(x) = unrolled_map((t,x)->t(x), m.t, x)

julia> @inferred m((1,2))
(2, 4)
``````

#3

It appears that I don’t need it; `map` works fine for both tuples and vectors:

``````(m::Many)(x) = map((t,x)->t(x), m.t, x)

@inferred m([1,2])
@inferred m((1,2))
@inferred m([1.0,2.0])
@inferred m((1.0,2))
``````

#4

Cool! IIRC `map` will bail out once your tuples get larger than ~15, so check if you need that.

#5

#6

Apparently `Vector` to `Vector` works fine even for a lot of elements (eg `N=1000` below), but `N=15` breaks type inference in

``````using Base.Test

struct One end
struct Two end

(::One)(x) = x+1
(::Two)(x) = x+2

struct Many{T}
t::T
end

(m::Many)(x) = map((t,x)->t(x), m.t, x)

N = 15
m = Many(ntuple(i->isodd(i) ? One() : Two(), N))
@inferred m(ones(N))
@inferred m(tuple(ones(N)...))
``````

Since ATM I need vector to vector, I will go with `map`.