Side discussion on gotos

Afaik, goto is a primitive. It is simply a decision of surface syntax that you use it as a macro instead of keyword. If you look at code_typed(...; optimize=false) and code_lowered you will see it all over the place. As far as I understood, Stefan’s solution disregards the abstract syntax tree (the thing manipulated by macros, with expressions) and instead considers lowered code and the resulting control flow graph. Lowered code does not contain loops:

julia> function f(A)
       x=A[1]
       @goto skip
       return y
       @label skip
       while x>0
       x-=1
       end
       x
       end;

julia> code_lowered(f, Tuple{Vector{Int}})
1-element Array{Core.CodeInfo,1}:
 CodeInfo(
2 1 ─      x = (Base.getindex)(A, 1)                                        │
3 └──      goto #3                                                          │
4 2 ─      return Main.y                                                    │
6 3 ┄ %4 = x > 0                                                            │
  └──      goto #5 if not %4                                                │
7 4 ─      x = x - 1                                                        │
  └──      goto #3                                                          │
9 5 ─      return x

In this sense, loops are not primitive structures in julia. Stefan’s rule needs to operate on a level between AST and lowered code: We see that currently, the lowering already decides whether bindings are local or global. With his rule, we would need to “semi-lower” without this knowledge, then search the CFG, then annotate local/global, and then go on as before. People who want to really understand scoping in top-level would need to understand the lowering process as well as parsing (AST construction).

PS. Thanks @StefanKarpinski for moving us out of the main thread!

1 Like