How is destructuring transformed\lowered

I have seen it mentioned before that:

function f((x,y))

is effectively transformed to

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?

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.

1 Like

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

What do you mean next?

Interfaces Β· The Julia Language

for i in iter   # or  "for i = iter"
    # body
end

is translated into:

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:

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:

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

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.

1 Like

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