# Constants not propagated when taking a slice of a tuple

**URL:** <https://discourse.julialang.org/t/constants-not-propagated-when-taking-a-slice-of-a-tuple/18618>\
**Category:** General Usage\
**Tags:** bug\
**Created:** [December 13, 2018, 2:28am UTC](https://discourse.julialang.org/t/constants-not-propagated-when-taking-a-slice-of-a-tuple/18618 "2018-12-13T02:28:34Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![cnliao](https://avatars.discourse-cdn.com/v4/letter/c/ce73a5/32.png) [@cnliao](https://discourse.julialang.org/u/cnliao)\
**Post date:** [December 13, 2018, 2:28am UTC](https://discourse.julialang.org/t/constants-not-propagated-when-taking-a-slice-of-a-tuple/18618/1 "2018-12-13T02:28:35Z")

</div>

I wrote some functions that shifts tuples and run into the following:

```julia
shiftleft(x1, xs...) = (xs..., x1) # (1,2,3) -> (2,3,1)
shiftright1(xs...) = (xs[end], xs[1:end-1]...) # (1,2,3) -> (3,1,2)
shiftright2(xs...) = (xs[end], reverse(Base.tail(reverse(xs)))...) # awkward, right?
@code_typed shiftleft(1,2,3) # infers fine
@code_typed shiftright1(1,2,3) # julia fails to decide the number of elements returned.
@code_typed shiftright2(1,2,3) # infers fine

```

Generally I find it hard to spot issues when type inference works in my mind but not work in julia. Can you shed some light on me ? Many Thanks.

---

<div class="post-metadata">

**Author:** ![tkf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkf/32/17635_2.png) [@tkf](https://discourse.julialang.org/u/tkf)\
**Post date:** [December 13, 2018, 11:43pm UTC](https://discourse.julialang.org/t/constants-not-propagated-when-taking-a-slice-of-a-tuple/18618/2 "2018-12-13T23:43:08Z")

</div>

It seems `getindex(t::Tuple, r::AbstractUnitRange{<:Real})` is made type unstable on purpose to help compiler [remove a couple uses of `ntuple` to help the compiler · JuliaLang/julia@c3f3b48 · GitHub](https://github.com/JuliaLang/julia/commit/c3f3b489d5c7e3267c545fa1c42351643fb71b96)

Reverting back to the old definition makes it type stable.

```julia
julia> shiftright1(xs...) = (xs[end], xs[1:end-1]...)
shiftright1 (generic function with 1 method)

julia> @code_typed shiftright1(1,2,3)
CodeInfo(
...
) => Tuple{Int64,Vararg{Int64,N} where N}

julia> Base.getindex(t::Tuple, r::AbstractUnitRange{<:Real}) = (o = first(r) - 1; ntuple(n -> t[o + n], length(r)))

julia> @code_typed shiftright1(1,2,3)
CodeInfo(
1 ─ %1 = (Base.getfield)(xs, 3, true)::Int64
│ %2 = (Base.add_int)(0, 1)::Int64
│ %3 = (Base.getfield)(xs, %2, true)::Int64
│ %4 = (Base.add_int)(0, 2)::Int64
│ %5 = (Base.getfield)(xs, %4, true)::Int64
│ %6 = (Core.tuple)(%1, %3, %5)::Tuple{Int64,Int64,Int64}
└── return %6
) => Tuple{Int64,Int64,Int64}

julia> VERSION
v"1.1.0-DEV.865"

```

---

<div class="post-metadata">

**Author:** ![cnliao](https://avatars.discourse-cdn.com/v4/letter/c/ce73a5/32.png) [@cnliao](https://discourse.julialang.org/u/cnliao)\
**Post date:** [December 14, 2018, 12:23am UTC](https://discourse.julialang.org/t/constants-not-propagated-when-taking-a-slice-of-a-tuple/18618/3 "2018-12-14T00:23:15Z")

</div>

Thank you! That’s very interesting. Would you elaborate on how type instability can help the compiler?

---

<div class="post-metadata">

**Author:** ![tkf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkf/32/17635_2.png) [@tkf](https://discourse.julialang.org/u/tkf)\
**Post date:** [December 14, 2018, 12:48am UTC](https://discourse.julialang.org/t/constants-not-propagated-when-taking-a-slice-of-a-tuple/18618/4 "2018-12-14T00:48:40Z")

</div>

Well, the commit message says “remove a couple uses of `ntuple` to help the compiler” so I just copied the phrase. My guess is that it makes it impossible to infer the type so that compiler gives up early which in turn makes JIT completion time shorter.

---

<div class="post-metadata">

**Author:** ![cnliao](https://avatars.discourse-cdn.com/v4/letter/c/ce73a5/32.png) [@cnliao](https://discourse.julialang.org/u/cnliao)\
**Post date:** [December 14, 2018, 12:53am UTC](https://discourse.julialang.org/t/constants-not-propagated-when-taking-a-slice-of-a-tuple/18618/5 "2018-12-14T00:53:53Z")

</div>

That make sense. By the way how did you spot this issue? (By your amazing InteracticeCodeSearch.jl I guess?) Do you think it is possible to automatically scan up a call chain to detect where type instability happens?

---

<div class="post-metadata">

**Author:** ![cnliao](https://avatars.discourse-cdn.com/v4/letter/c/ce73a5/32.png) [@cnliao](https://discourse.julialang.org/u/cnliao)\
**Post date:** [December 14, 2018, 12:56am UTC](https://discourse.julialang.org/t/constants-not-propagated-when-taking-a-slice-of-a-tuple/18618/6 "2018-12-14T00:56:10Z")

</div>

I unmarked your answer as the solution so that this post can live longer:wink:

---

<div class="post-metadata">

**Author:** ![tkf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkf/32/17635_2.png) [@tkf](https://discourse.julialang.org/u/tkf)\
**Post date:** [December 14, 2018, 2:13am UTC](https://discourse.julialang.org/t/constants-not-propagated-when-taking-a-slice-of-a-tuple/18618/7 "2018-12-14T02:13:00Z")

</div>

I just guessed `xs[1:end-1]` was the problematic part and then ran `xs = (1, 2, 3)`; `@edit xs[1:2]`. It led me to the code using `Vector` which didn’t seem very nice for the type system so I ran `git blame` to find the commit.

(`@search` from InteractiveCodeSearch.jl actually does not work this case since it evaluates `xs[1:2]`. It would be nice to support this but `@edit` works perfectly fine so I’m not super motivated to fix this at the moment…)

> [@cnliao](#):
>
> Do you think it is possible to automatically scan up a call chain to detect where type instability happens?

I just read `?@code_typed` and it turned out you can pass `optimize=false` to do:

```julia
julia> @code_typed optimize=false shiftright1(1,2,3)
CodeInfo(
1 ─ %1 = (Base.lastindex)(xs)::Const(3, false)
│ %2 = (Base.getindex)(xs, %1)::Int64
│ %3 = (Core.tuple)(%2)::Tuple{Int64}
│ %4 = (Base.lastindex)(xs)::Const(3, false)
│ %5 = (%4 - 1)::Const(2, false)
│ %6 = (1:%5)::Const(1:2, false)
│ %7 = (Base.getindex)(xs, %6)::Tuple{Vararg{Int64,N} where N}
│ %8 = (Core._apply)(Core.tuple, %3, %7)::Tuple{Int64,Vararg{Int64,N} where N}
└── return %8
) => Tuple{Int64,Vararg{Int64,N} where N}

```

which tells you that the type instability happens at `getindex`. It only takes care of the “first level” of the call chain but I guess it can be handy.

---

<div class="post-metadata">

**Author:** ![tkf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkf/32/17635_2.png) [@tkf](https://discourse.julialang.org/u/tkf)\
**Post date:** [December 14, 2018, 2:15am UTC](https://discourse.julialang.org/t/constants-not-propagated-when-taking-a-slice-of-a-tuple/18618/8 "2018-12-14T02:15:37Z")

</div>

I think it would be very useful if slicing is type stable. I don’t know what’s the best way to get attention from core devs, though. Maybe move to “internals” category?

---

<div class="post-metadata">

**Author:** ![cnliao](https://avatars.discourse-cdn.com/v4/letter/c/ce73a5/32.png) [@cnliao](https://discourse.julialang.org/u/cnliao)\
**Post date:** [December 14, 2018, 2:28am UTC](https://discourse.julialang.org/t/constants-not-propagated-when-taking-a-slice-of-a-tuple/18618/9 "2018-12-14T02:28:44Z")

</div>

> [@tkf](#):
>
> I just read `?@code_typed` and it turned out you can pass `optimize=false` to do:

Thank you! That’s already way better than what I am doing now: calling methods and following calls in base/\*.jl…

> [@tkf](#):
>
> I just guessed `xs[1:end-1]` was the problematic part and then ran `xs = (1, 2, 3)` ; `@edit xs[1:2]` .

I will be a happy user from today on 😃

> [@tkf](#):
>
> I don’t know what’s the best way to get attention from core devs, though.

[Issue filed.](https://github.com/JuliaLang/julia/issues/30386)

---

<div class="post-metadata">

**Author:** ![tkf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkf/32/17635_2.png) [@tkf](https://discourse.julialang.org/u/tkf)\
**Post date:** [December 14, 2018, 3:15am UTC](https://discourse.julialang.org/t/constants-not-propagated-when-taking-a-slice-of-a-tuple/18618/10 "2018-12-14T03:15:44Z")

</div>

Thanks for filing the issue!

---

<div class="post-metadata">

**Author:** ![cnliao](https://avatars.discourse-cdn.com/v4/letter/c/ce73a5/32.png) [@cnliao](https://discourse.julialang.org/u/cnliao)\
**Post date:** [December 14, 2018, 6:20am UTC](https://discourse.julialang.org/t/constants-not-propagated-when-taking-a-slice-of-a-tuple/18618/11 "2018-12-14T06:20:53Z")

</div>

JeffBezanson [suggested](https://github.com/JuliaLang/julia/issues/30386#issuecomment-447200325) a `butlast` function. That indeed sounds nice. Even so as we already have `Base.tail`.

```julia
butlast(t::Tuple) = _butlast(t...)
_butlast(x1) = ()
_butlast(x1, xs...) = (x1, _butlast(xs...)...)

shiftright(xs...) = (xs[end], butlast(xs)...)
@code_typed shiftright(1,2,3)

```

---

<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:** [December 14, 2018, 7:10am UTC](https://discourse.julialang.org/t/constants-not-propagated-when-taking-a-slice-of-a-tuple/18618/12 "2018-12-14T07:10:06Z")

</div>

> [@cnliao](#):
>
> JeffBezanson [suggested](https://github.com/JuliaLang/julia/issues/30386#issuecomment-447200325) a `butlast` function.

We [have one](https://github.com/JuliaLang/julia/blob/77a7d92e91769146435fe92548d253fa18740840/src/utils.scm#L65-L68), just not in the right place 😉
