# Exporting variables from local scope introduced by macro

**URL:** https://discourse.julialang.org/t/exporting-variables-from-local-scope-introduced-by-macro/24013
**Category:** General Usage
**Tags:** metaprogramming
**Created:** [May 9, 2019, 3:52am UTC](https://discourse.julialang.org/t/exporting-variables-from-local-scope-introduced-by-macro/24013 "2019-05-09T03:52:05Z")
**Posts on this page:** 3
**Page:** 1

<div class="post-metadata">

### Author: ![baggepinnen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baggepinnen/32/693_2.png) [@baggepinnen](https://discourse.julialang.org/u/baggepinnen)
#### Post date: [May 9, 2019, 3:52am UTC](https://discourse.julialang.org/t/exporting-variables-from-local-scope-introduced-by-macro/24013/1 "2019-05-09T03:52:05Z")

</div>

I want to write a macro that, before the enclosed expressions is run, activates “unsafe mode” and deactivates this mode again afterwards, kind of like

```julia
@unsafe_mode my_expr

```

translating to

```julia
unsafe(true)
my_expr
unsafe(false)

```

This is not too hard to write, but it gets trickier. The expression passed in by the user might fail, and must thus be enclosed in a `try/finally` block, so that `unsafe(false)` is always run no matter what. This is where I run into problems. If `my_expr` containts an assignment, I want to declare those assigned variables local outside of the try block so that the user can use them. I have not managed to do this. Here is my attempt

```julia
using MacroTools
state = false
unsafe_state() = state
unsafe_state(x) = (global state = x)

macro unsafe_comparisons(ex)
    @capture(ex, assigned_vars__ = y_) # if assigned_vars is empty do something
    quote
        previous_state = unsafe_state()
        unsafe_state(true)
        local $(esc.(assigned_vars)...)
        local res
        try
            res = ($(esc(ex)))
        finally
            unsafe_state(previous_state)
        end
        res
    end
end

julia> @unsafe a = 1
ERROR: syntax: invalid syntax in "local" declaration

```

I also tried

```julia
macro unsafe(ex)
    @capture(ex, assigned_vars__ = y_)
    ex1 = quote
        previous_state = unsafe_state()
        unsafe_state(true)
    end
    ex2 =Expr(:local, esc.(assigned_vars)...)
    quote 
        $ex1
        $ex2
        local res
        try
            res = ($(esc(ex)))
        finally
            unsafe_state(previous_state)
        end
        res
    end
end

julia> @unsafe a = 1
1

julia> a
ERROR: UndefVarError: a not defined

```

which returns the correct value but does not define `a`.  
I’m kind of lost at this point as to what to try 😕

Edit:  
The second version actually works if the macro is used inside a function

```julia
julia> test() = (@unsafe(a = 1); a)
test (generic function with 1 method)

julia> test()
1

```

It does however not work if the macro is used in global scope. I suspect that when used in global scope, I have to somehow declare the assigned variables local instead of global, but I do not know how to detect this.

---

<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: [May 9, 2019, 6:30am UTC](https://discourse.julialang.org/t/exporting-variables-from-local-scope-introduced-by-macro/24013/2 "2019-05-09T06:30:00Z")

</div>

You could perhaps use `Expr(:tryfinally, ...)` as in [https://github.com/KristofferC/TimerOutputs.jl/blob/b19ecbf2b044c99f783ddb7ec53c5d0d7bc235d3/src/TimerOutput.jl#L216-L221](https://github.com/KristofferC/TimerOutputs.jl/blob/b19ecbf2b044c99f783ddb7ec53c5d0d7bc235d3/src/TimerOutput.jl#L216-L221).

---

<div class="post-metadata">

### Author: ![baggepinnen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baggepinnen/32/693_2.png) [@baggepinnen](https://discourse.julialang.org/u/baggepinnen)
#### Post date: [May 9, 2019, 6:33am UTC](https://discourse.julialang.org/t/exporting-variables-from-local-scope-introduced-by-macro/24013/3 "2019-05-09T06:33:35Z")

</div>

Thanks for your reply!  
I managed to circumvent the exporting problem with a little trick, I deconstruct the full result of the user expression into the user-defined assigned variables after the try-finally block:

```julia
macro unsafe(ex)
    ex2 = if @capture(ex, assigned_vars__ = y_)
        if length(assigned_vars) == 1
            esc(assigned_vars[1])
        else
            esc.(assigned_vars[1].args)
        end
    else
        :(res)
    end
    quote
        previous_state = USE_UNSAFE_COMPARIONS[]
        unsafe_comparisons(true, verbose=false)
        local res
        try
            res = ($(esc(ex)))
        finally
            unsafe_comparisons(previous_state, verbose=false)
        end
        $ex2 = res
    end
end

```
