# Inference for tuple of callable objects

**URL:** <https://discourse.julialang.org/t/inference-for-tuple-of-callable-objects/5354>\
**Category:** General Usage\
**Tags:** question\
**Created:** [August 13, 2017, 12:38pm UTC](https://discourse.julialang.org/t/inference-for-tuple-of-callable-objects/5354 "2017-08-13T12:38:48Z")\
**Posts on this page:** 6\
**Page:** 1

<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:** [August 13, 2017, 12:38pm UTC](https://discourse.julialang.org/t/inference-for-tuple-of-callable-objects/5354/1 "2017-08-13T12:38:48Z")

</div>

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

```julia
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:

```julia
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?

---

<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:** [August 13, 2017, 12:56pm UTC](https://discourse.julialang.org/t/inference-for-tuple-of-callable-objects/5354/2 "2017-08-13T12:56:21Z")

</div>

`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](https://github.com/cstjean/Unrolled.jl)

```julia
julia> using Unrolled

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

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

```

---

<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:** [August 13, 2017, 1:19pm UTC](https://discourse.julialang.org/t/inference-for-tuple-of-callable-objects/5354/3 "2017-08-13T13:19:12Z")

</div>

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

```julia
(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))

```

---

<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:** [August 13, 2017, 1:52pm UTC](https://discourse.julialang.org/t/inference-for-tuple-of-callable-objects/5354/4 "2017-08-13T13:52:58Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![tkoolen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkoolen/32/1603_2.png) [@tkoolen](https://discourse.julialang.org/u/tkoolen)\
**Post date:** [August 13, 2017, 3:56pm UTC](https://discourse.julialang.org/t/inference-for-tuple-of-callable-objects/5354/5 "2017-08-13T15:56:57Z")

</div>

See also [GitHub - yuyichao/FunctionWrappers.jl](https://github.com/yuyichao/FunctionWrappers.jl).

---

<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:** [August 14, 2017, 11:10am UTC](https://discourse.julialang.org/t/inference-for-tuple-of-callable-objects/5354/6 "2017-08-14T11:10:49Z")

</div>

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

```julia
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`.
