Side discussion on gotos


#1

Sorry for off-topic! (if somebody has rights then please cut it into another one)

I meant that understanding macro means understanding code to which it is expanded.

macro goto(name::Symbol)
    return esc(Expr(:symbolicgoto, name))
end

julia> @macroexpand @goto a
:($(Expr(:symbolicgoto, :a)))

I mean that there is not “standard” syntax for goto in Julia language and @goto macro is expanded into something I am not able to understand in this moment. I just feel that it is similar to something like this:

# ! mighty lisp please translate this comment as label A
if repeat
   # ! mighty lisp please translate this comment as go to label A
end

BTW how to write equivalent code with these macros expanded?

julia> @macroexpand @label A
:($(Expr(:symboliclabel, :A)))

julia> begin
       i = 1
       :($(Expr(:symboliclabel, :A)))   # this doesn't work
       i += 1
       if i<10 
          :($(Expr(:symbolicgoto, :a)))  # this doesn't work
       end
       end

New scope solution
#2

You can just post a reply in a new thread instead of asking an admin to do it.


#3

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!


New scope solution
#4

Are you able to write @goto and @label expanded?

julia> function f()
             i = 1
             eval(:($(Expr(:symboliclabel, :A))))   # (1)
             i += 1
             if i<10 
                eval(:($(Expr(:symbolicgoto, :A))))  # (2)
             end
             end
julia>   f()
ERROR: syntax: label "A" referenced but not defined

similar (*) error if we change (1) to @label A or if we change (2) to @goto A. (obviously if we change both it works :wink: )

It is because eval is “post-lisp-phase” execution?

(*) second one is without stack trace which support “lisp-phase” hypothesis…


#5
julia> @eval begin
       function f()
           i = 1
           $(Expr(:symboliclabel, :A))
           i += 1
           if i<10
               println(i)
               $(Expr(:symbolicgoto, :A))
           end
       end
       end
f (generic function with 3 methods)

julia> f()
2
3
4
5
6
7
8
9