# Inference failure on tuple

**URL:** <https://discourse.julialang.org/t/inference-failure-on-tuple/5697>\
**Category:** General Usage\
**Created:** [September 3, 2017, 4:57pm UTC](https://discourse.julialang.org/t/inference-failure-on-tuple/5697 "2017-09-03T16:57:41Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![gasagna](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gasagna/32/1275_2.png) [@gasagna](https://discourse.julialang.org/u/gasagna)\
**Post date:** [September 3, 2017, 4:57pm UTC](https://discourse.julialang.org/t/inference-failure-on-tuple/5697/1 "2017-09-03T16:57:42Z")

</div>

It seems like the compiler cannot infer the type of the tuple `b` in the below MWE, while I think it should. This results in suboptimal performance. I can easily work around this, at the expense of code readability. Worth reporting?

```julia
js(n) = ntuple(i->i, n)
foo(n, s) = exp.(im.*js(n).*s)

function bar(s::Real)
    n = 5
    b = foo(n, s)
    sum(b)
end

s = 1.0
@code_warntype bar(s)

Variables:
  #self#::#bar
  s::Float64
  n::Int64
  b::ANY

Body:
  begin # line 11:
      b::ANY = $(Expr(:invoke, MethodInstance for foo(::Int64, ::Float64), :(Main.foo), 5, :(s))) # line 12:
      return (Main.sum)(b::ANY)::ANY
  end::ANY

```

---

<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:** [September 3, 2017, 6:05pm UTC](https://discourse.julialang.org/t/inference-failure-on-tuple/5697/2 "2017-09-03T18:05:46Z")

</div>

Replacing `n = 5` with `n = Val{5}` (or `Val(5)` on nightly or with Compat after [https://github.com/JuliaLang/Compat.jl/pull/399](https://github.com/JuliaLang/Compat.jl/pull/399)) fixes the issue. I guess constant propagation isn’t good enough yet to infer the return type of `ntuple(i -> i, n)` with `n = 5`.

---

<div class="post-metadata">

**Author:** ![gasagna](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gasagna/32/1275_2.png) [@gasagna](https://discourse.julialang.org/u/gasagna)\
**Post date:** [September 3, 2017, 6:20pm UTC](https://discourse.julialang.org/t/inference-failure-on-tuple/5697/3 "2017-09-03T18:20:55Z")

</div>

Yeah, using `Val` is a typical solution to such issues. Will report an issue, just to track improvements in inference.

---

<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:** [September 3, 2017, 8:36pm UTC](https://discourse.julialang.org/t/inference-failure-on-tuple/5697/4 "2017-09-03T20:36:28Z")

</div>

I don’t think it’s a matter of constant propagation; `js` accepts an `Int` and returns a tuple of variable length, so it’s necessarily type-unstable.

---

<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:** [September 3, 2017, 8:57pm UTC](https://discourse.julialang.org/t/inference-failure-on-tuple/5697/5 "2017-09-03T20:57:15Z")

</div>

Maybe constant propagation isn’t the right term to use (I’m certainly not an expert on this), but I could imagine it being possible in the future that `js`, `foo`, and `ntuple` get inlined, and that after dead code elimination the compiler can figure out that the only possibility is that `js(n)` is an `NTuple{5,Int64}`, making everything type stable.

In some different cases, the compiler can already figure it out:

```julia
julia> f(x) = isbits(x) ? zero(x) : rand(Int, x[1])
f (generic function with 1 method)

julia> @code_warntype f(1)
Variables:
  #self#::#f
  x::Int64

Body:
  begin 
      return 0
  end::Int64

julia> @code_warntype f([4])
Variables:
  #self#::#f
  x::Array{Int64,1}

Body:
  begin 
      goto 2
      2: 
      SSAValue(0) = (Base.arrayref)(x::Array{Int64,1}, 1)::Int64
      return $(Expr(:invoke, MethodInstance for rand!(::MersenneTwister, ::Array{Int64,1}), :(Base.Random.rand!), :(Base.Random.GLOBAL_RNG), :($(Expr(:foreigncall, :(:jl_alloc_array_1d), Array{Int64,1}, svec(Any, Int64), Array{Int64,1}, 0, SSAValue(0), 0)))))
  end::Array{Int64,1}

```

---

<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:** [September 3, 2017, 9:20pm UTC](https://discourse.julialang.org/t/inference-failure-on-tuple/5697/6 "2017-09-03T21:20:21Z")

</div>

> [@tkoolen](#):
>
> In some different cases, the compiler can already figure it out:

That’s because `isbits(x)` is a property derivable from `x`’s type.

---

<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:** [September 3, 2017, 9:34pm UTC](https://discourse.julialang.org/t/inference-failure-on-tuple/5697/7 "2017-09-03T21:34:23Z")

</div>

Sure, and nothing like the original example is currently inferable, but is the dead code elimination scenario I was talking about such a stretch for some time in the future?

---

<div class="post-metadata">

**Author:** ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)\
**Post date:** [September 3, 2017, 9:48pm UTC](https://discourse.julialang.org/t/inference-failure-on-tuple/5697/8 "2017-09-03T21:48:19Z")

</div>

What do you mean? It(dead code elimination)'s already implemented as what you’ve seen.

---

<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:** [September 4, 2017, 1:28am UTC](https://discourse.julialang.org/t/inference-failure-on-tuple/5697/9 "2017-09-04T01:28:06Z")

</div>

Yes, but it looks to me like dead code elimination currently comes after type inference is already done. This is totally reasonable of course, but there are cases, like the one in the OP, where (re-)running type inference _after_ dead code elimination (at the Julia AST level, I suppose) could be beneficial, in the sense of potentially producing more performant code without the user or Julia Base developer having to jump through additional hoops (user having to use `Val`, addition of the `Val` methods for `ntuple` in base, in the OP case).

Here’s a simpler example:

```julia
function baz1()
    n = 2
    if n > 1
        1
    else
        1.
    end
end

baz2() = 1

```

Even though `baz1` and `baz2` always return the same underlying value, 1, `baz1` returns it boxed, and the `code_typed`, `code_llvm`, and `code_native` are all different for `baz1` and `baz2`. This is despite the fact that dead code elimination happens (I believe) for `baz1` between the `code_typed` and the `code_llvm` stage.

---

<div class="post-metadata">

**Author:** ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)\
**Post date:** [September 4, 2017, 1:39am UTC](https://discourse.julialang.org/t/inference-failure-on-tuple/5697/10 "2017-09-04T01:39:28Z")

</div>

> [@tkoolen](#):
>
> dead code elimination

You mean constant propagation? (and your `baz1` is missing inferred purity and not dead code elimination).  
And in anycase, there’s [Do some constant propagation before type inference runs · Issue #5560 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/5560) already.

---

<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:** [September 4, 2017, 1:52am UTC](https://discourse.julialang.org/t/inference-failure-on-tuple/5697/11 "2017-09-04T01:52:08Z")

</div>

That’s what I called it initially, but I wasn’t sure that it was the right term, so I tried to explain it in other terms. Thanks for the pointer to the issue.
