# A macro to inspect global variables used in a function?

**URL:** <https://discourse.julialang.org/t/a-macro-to-inspect-global-variables-used-in-a-function/119119>\
**Category:** General Usage\
**Created:** [September 6, 2024, 11:50am UTC](https://discourse.julialang.org/t/a-macro-to-inspect-global-variables-used-in-a-function/119119 "2024-09-06T11:50:39Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![pierre-haessig](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pierre-haessig/32/217129_2.png) [@pierre-haessig](https://discourse.julialang.org/u/pierre-haessig)\
**Post date:** [September 6, 2024, 11:50am UTC](https://discourse.julialang.org/t/a-macro-to-inspect-global-variables-used-in-a-function/119119/1 "2024-09-06T11:50:39Z")

</div>

Hello,  
When packing inside a function a code previously developed on the Main module in the command line (e.g. work done in a Jupyter notebook), it’s easy to forget to put parameters as function arguments. See e.g. this simplified example:

```julia
# first REPL work:
a = 1.0
b = 2.0
c = sin(a+b) # 0.14112

# Then consolidated in a function:
fun_c(a) = sin(a+b) # oops, b is forgotten as an argument
# quick test:
fun_c(a) # 0.14112 → apparently it works, but will in a later session...

```

Now, it was mentioned e.g. in [Benny’s answer here](https://discourse.julialang.org/t/functions-with-independent-global-scopes/103703/8) that the use of a global variable inside a function can be spotted with `@code_warntype`, as it gets prefixed by `Main.`:

```julia
julia> @code_warntype fun_c(a)
MethodInstance for fun_c(::Float64)
  from fun_c(a) @ Main REPL[4]:1
Arguments
  #self#::Core.Const(fun_c)
  a::Float64
Body::Any
1 ─ %1 = (a + Main.b)::Any # Ohoh Main.b...
│ %2 = Main.sin(%1)::Any
└── return %2

```

However, this needs to be distinguished from the legitimate use of `Main.sim`. Also, it a largish real life function (ex: large JuMP model), these `Main.variable` text fragments may get hidden.

So my question is: _is there a simple macro to just list all the external references used in a function?_

---

<div class="post-metadata">

**Author:** ![bertschi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bertschi/32/33462_2.png) [@bertschi](https://discourse.julialang.org/u/bertschi)\
**Post date:** [September 6, 2024, 6:04pm UTC](https://discourse.julialang.org/t/a-macro-to-inspect-global-variables-used-in-a-function/119119/2 "2024-09-06T18:04:59Z")

</div>

I’m not aware of such a macro … it seems the information is easily available from the lowered code though and the following might be a start:

```julia
macro warn_nonconst_globals(expr)
    :(let low = @code_lowered($expr)
          walker(x) = if x isa GlobalRef && !isconst(x); println(x) end
          MacroTools.postwalk.(Ref(walker), low.code)
          nothing
     end)
end

```

```julia-repl
julia> @warn_nonconst_globals fun_c(a)
Main.b

```

---

<div class="post-metadata">

**Author:** ![alfaromartino](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/alfaromartino/32/52986_2.png) [@alfaromartino](https://discourse.julialang.org/u/alfaromartino)\
**Post date:** [September 6, 2024, 8:13pm UTC](https://discourse.julialang.org/t/a-macro-to-inspect-global-variables-used-in-a-function/119119/3 "2024-09-06T20:13:10Z")

</div>

Note that `@code_warntype` will show any type instability in red. This implies that if you have included any global variable, the result will include some red line.

In case your question is more general about forgetting to add variables, it’s probably a symptom that you have long functions. This means that if you have long functions, it’s probably better if you split them into smaller functions.  
Overall, it’s always recommend to have self contained functions. As for parameters, you can handle them by having a tuple of them that you unpack in the first line of the function. Alternatively, you could define the parameters globally as `const` if you know they won’t change their value.

edit: maybe this [package](https://discourse.julialang.org/t/ann-dispatchdoctor-jl-offers-you-a-prescription-for-type-stability/114837) that forces you to write stable functions can be helpful?

---

<div class="post-metadata">

**Author:** ![pierre-haessig](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pierre-haessig/32/217129_2.png) [@pierre-haessig](https://discourse.julialang.org/u/pierre-haessig)\
**Post date:** [September 9, 2024, 2:22pm UTC](https://discourse.julialang.org/t/a-macro-to-inspect-global-variables-used-in-a-function/119119/4 "2024-09-09T14:22:43Z")

</div>

Very useful, thanks!

Testing it on largish functions, the only improvements I see are:

- memorize symbols already met to avoid duplicate prints
- also analyze sub-functions (“Step Into” using debuggers’ vocabulary)

Also, I found a tricky case where the global gets undetected when used in a JuMP macro:

```julia
# using JuMP; model creation...
@variable(model, 0 <= x <= x_bound)

```

→ `x_bound` isn’t detected. And detecting it involves _not sending a false positive_ about `x` which ends up being locally bound by `@variable`…
