# How is destructuring transformed\\lowered

**URL:** <https://discourse.julialang.org/t/how-is-destructuring-transformed-lowered/22421>\
**Category:** Internals & Design\
**Created:** [March 27, 2019, 5:07pm UTC](https://discourse.julialang.org/t/how-is-destructuring-transformed-lowered/22421 "2019-03-27T17:07:14Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![ndinsmore](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ndinsmore/32/7433_2.png) [@ndinsmore](https://discourse.julialang.org/u/ndinsmore)\
**Post date:** [March 27, 2019, 5:07pm UTC](https://discourse.julialang.org/t/how-is-destructuring-transformed-lowered/22421/1 "2019-03-27T17:07:14Z")

</div>

I have seen it mentioned before that:

```julia
function f((x,y))

```

is effectively transformed to

```julia
function f(temp)
    x , y = temp

```

But I don’t think that it is documented anywhere how `x , y = temp` is transformed.

Could somebody please explain?

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [March 27, 2019, 5:13pm UTC](https://discourse.julialang.org/t/how-is-destructuring-transformed-lowered/22421/2 "2019-03-27T17:13:58Z")

</div>

> [@ndinsmore](#):
>
> `x , y = temp`

```julia
julia> Meta.@lower x , y = temp
:($(Expr(:thunk, CodeInfo(
 1 ─ %1 = (Base.indexed_iterate)(temp, 1) │
 │ %2 = (Core.getfield)(%1, 1) │
 │ x = %2 │
 │ #s1 = (Core.getfield)(%1, 2) │
 │ %5 = (Base.indexed_iterate)(temp, 2, #s1) │
 │ %6 = (Core.getfield)(%5, 1) │
 │ y = %6 │
 └── return temp │
))))

```

It’s just a slightly fancier version of manually unrolled iteration.

---

<div class="post-metadata">

**Author:** ![ndinsmore](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ndinsmore/32/7433_2.png) [@ndinsmore](https://discourse.julialang.org/u/ndinsmore)\
**Post date:** [March 27, 2019, 7:02pm UTC](https://discourse.julialang.org/t/how-is-destructuring-transformed-lowered/22421/3 "2019-03-27T19:02:44Z")

</div>

How about the destructuring of `next` in the lowering of a `for` loop?  
Does it get lower straight to a `getfield`?

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [March 27, 2019, 7:04pm UTC](https://discourse.julialang.org/t/how-is-destructuring-transformed-lowered/22421/4 "2019-03-27T19:04:41Z")

</div>

What do you mean `next`?

---

<div class="post-metadata">

**Author:** ![ndinsmore](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ndinsmore/32/7433_2.png) [@ndinsmore](https://discourse.julialang.org/u/ndinsmore)\
**Post date:** [March 27, 2019, 7:27pm UTC](https://discourse.julialang.org/t/how-is-destructuring-transformed-lowered/22421/5 "2019-03-27T19:27:21Z")

</div>

> [Interfaces · The Julia Language](https://docs.julialang.org/en/v1.2-dev/manual/interfaces/)
> 
> ```julia
> for i in iter # or "for i = iter"
> # body
> end
> 
> ```
> 
> is translated into:
> 
> ```julia
> next = iterate(iter)
> while next !== nothing
> (i, state) = next
> # body
> next = iterate(iter, state)
> end
> 
> ```

I know that portion of the documenation is out of date it is more like:

```julia
next = iterate(iter)
next === nothing && @goto loop_end
    @label loop_head
    (i, state) = next
    # body
    next = iterate(iter, state)
    next === nothing && @goto loop_end
    @goto loop_head
@label loop_end

```

But it appears that lowering of for today may be breaking the interface by skiping the `indexed_iterate` of destructuring and going straight to:

```julia
next = iterate(iter)
next === nothing && @goto loop_end
    @label loop_head
    i = getfield(next,1)
    state = getfield(next,2)
    # body
    next = iterate(iter, state)
    next === nothing && @goto loop_end
    @goto loop_head
@label loop_end

```

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [March 27, 2019, 7:33pm UTC](https://discourse.julialang.org/t/how-is-destructuring-transformed-lowered/22421/6 "2019-03-27T19:33:02Z")

</div>

Yup. We should add an assertion to guarantee that `iterate` returns a tuple like it’s supposed to. I’d guess it’s this way because `for` loops are extraordinarily performance sensitive.

> <https://github.com/JuliaLang/julia/issues/25464>
>
> … and can have a very unintuitive error if it doesn't.
> 
> \`\`\`
> struct Dummy; end…;
> Base.iterate(::Dummy) = \[1,2\]
> Base.iterate(::Dummy, x) = nothing
> f() = for i in Dummy(); println(i); end
> 
> julia\> f()
> ERROR: BoundsError: attempt to access 2-element Array{Int64,1} at index \[1\]
> Stacktrace:
> \[1\] f() at ./REPL\[14\]:1
> \[2\] top-level scope at none:0
> 
> julia\> @code\_typed f()
> CodeInfo(
> 1 1 ─ %1 = invoke Base.vect(1::Int64, 2::Vararg{Int64,N} where N)::Array{Int64,1} │╻ iterate
> │ %2 = Base.not\_int(false)::Bool │
> └── goto 3 if not %2 │
> 2 ─ Core.getfield(%1, 1) │
> └── unreachable │
> 3 ┄ return nothing │
> 4 ─ goto 3 │
> ) =\> Nothing
> \`\`\`
> 
> This is because it uses \`getfield\` to get the first slot no matter what — so it can lead to nonsensical bounds errors or other surprises. I figure this might change with #25261, but I'm posting it as an issue to make sure it doesn't get forgotten. Originally reported by @Phlogistique on Slack (thanks!).
> 
> (Edit: updated to \`iterate\`)

---

<div class="post-metadata">

**Author:** ![ndinsmore](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ndinsmore/32/7433_2.png) [@ndinsmore](https://discourse.julialang.org/u/ndinsmore)\
**Post date:** [March 27, 2019, 8:28pm UTC](https://discourse.julialang.org/t/how-is-destructuring-transformed-lowered/22421/7 "2019-03-27T20:28:21Z")

</div>

I think I understand the reasoning but check out the benchmark here

> [@Iterator transformation results in 40% time reduction in Iteration over arrays](https://discourse.julialang.org/t/iterator-transformation-results-in-40-time-reduction-in-iteration-over-arrays/22428):
>
> Recently it has bugged me that for i in 1:length(array) @inbounds v=array[i] body ... end Was on the order of 30 % faster than: for v in array body ... end So I wanted to see if I could transform the latter into the former. The solution I came up with is a little hacky at the moment but it works & doesn’t change the two argument iterate construct. This has been updated to include a fix to include getindex. # B original iterator type # I new iterator type # IE eltype of I …

> [@Iterator transformation results in 40% time reduction in Iteration over arrays](https://discourse.julialang.org/t/iterator-transformation-results-in-40-time-reduction-in-iteration-over-arrays/22428/1):
>
> For the mean time we need the following functions for benchmarking:
> 
> ```julia
> function for_sum(iter)
> ret=eltype(iter)(0)
> for v in iter
> ret += v
> end
> return ret
> end
> 
> # goto_sum is needed because currently for is not lowered with the proper destructuring of next
> function goto_sum(iter)
> ret=eltype(iter)(0)
> next = iterate(iter)
> (next === nothing) && @goto loop_end
> @label loop_head
> (v, state) = next
> ret+=v
> next = iterate(iter, state)
> next === nothing && @goto loop_end
> @goto loop_head
> @label loop_end
> return ret
> end
> 
> ```
> 
> Lets sanity check their equivlence:
> 
> ```julia
> julia> a=collect(1:1000);
> 
> julia> for_sum(a)
> 500500
> 
> julia> goto_sum(a)
> 500500
> 
> julia> @benchmark for_sum($a)
> BenchmarkTools.Trial: 
> memory estimate: 0 bytes
> allocs estimate: 0
> --------------
> minimum time: 78.688 ns (0.00% GC)
> median time: 83.785 ns (0.00% GC)
> mean time: 91.614 ns (0.00% GC)
> maximum time: 883.004 ns (0.00% GC)
> --------------
> samples: 10000
> evals/sample: 964
> 
> julia> @benchmark goto_sum($a)
> BenchmarkTools.Trial: 
> memory estimate: 0 bytes
> allocs estimate: 0
> --------------
> minimum time: 78.688 ns (0.00% GC)
> median time: 83.778 ns (0.00% GC)
> mean time: 91.086 ns (0.00% GC)
> maximum time: 793.855 ns (0.00% GC)
> --------------
> samples: 10000
> evals/sample: 957
> 
> ```
