Todd
Todd

Reputation: 495

Julia globally scope all variables in a loop (temporarily)

When I'm prototyping and debugging code in Matlab, I can run a script and immediately inspect and edit all variables in that script when it stops running (either successfully or due to failure).

In Julia, variables inside a loop are locally scoped. While this is fine once I'm satisfied I have things working, I can't inspect variables in the REPL. The only way I can think to get around this is to list every variable in the loop as a global. Then I would have to edit that line every time I change a variable name or introduce a new one. Adding/changing variables is quite common when I'm experimenting and not fully sure what I'm doing yet. Is there a better way to do this?

Upvotes: 0

Views: 238

Answers (1)

novatena
novatena

Reputation: 196

I came up with the following very basic and simple macro. The idea is to modify the expression by adding a print statement for every assignment.

To use it, just add @add_print before the function or block of expressions you want.

However, the best solution would be using the Gallium debugger

walk(ex) = nothing

function walk(ex::Expr)
    for i in 1:length(ex.args)
        subex = ex.args[i]
        #println(subex)
        walk(subex)
        if isa(subex, Expr) && subex.head in Set([:(=), :(+=), :(-=), :(*=), :(/=)]) && ex.head == :block
            #println(subex)
            line = "line unknown:"
            if i > 1 && ex.args[i-1].head == :line
                line = "line $(ex.args[i-1].args[1])"
            end
            var = string(subex)
            ex.args[i] = :(
                begin
                    $subex
                    println($line)
                    println($var, " -> ", $(subex.args[1]))
                end
            )
        elseif ex.head == :block && isa(subex, Symbol)
            ex.args[i] = :(
                begin
                    println($subex)
                    $subex
                end
            )
        end
    end
end

macro add_print(ex)
    walk(ex)
    ex
end

Demo:

@add_print function binary_search(v, val)
    if v[1] > val || v[end] < val
        return 0
    end
    left = 1
    right = length(v)
    while left < right
        mid = div(left + right, 2)
        if v[mid] < val
            left = mid + 1
        else
            right = mid
        end
    end
    left
end

binary_search([1, 3, 4, 5, 7, 9], 4)

julia> binary_search([1, 3, 4, 5, 7, 9], 4)
line 5
left = 1 -> 1
line 6
right = length(v) -> 6
line 8
mid = div(left + right,2) -> 3
line 12
right = mid -> 3
line 8
mid = div(left + right,2) -> 2
line 10
left = mid + 1 -> 3
3

Upvotes: 1

Related Questions