Error escaping a variable in a module using JuMP

I’m working to update a module compatible with JuMP v1.1.1 to the newest version of JuMP. Within the module is code similar to:

module HoldBug

using JuMP

export @mytest

macro mytest(m,F)
    m = esc(m)
    x = esc(F)
    :(@NLconstraint( $(m), $(x) <= 4) )

end # module HoldBug

using .HoldBug
using JuMP

m = Model()


@macroexpand @mytest(m,x)


In the newest version of JuMP I get

UndefVarError: x not defined. 

Expanding the macro reveals the issue, in JuMP1.4 the variable x is being held by HoldBug

var"#4###315" = JuMP.Expr(:escape, Main.HoldBug.x)

In JuMP1.1, it looks like this

JuMP._parse_NL_expr_runtime(m, x, var"#5#tape", var"#7###315", var"#6#values")

Does anybody have advice on how to work around this?



Writing macros that call macros is very difficult to get correct. You need to properly escape things.

julia> module HoldBug
       using JuMP
       macro mytest(m, F)
           return esc(:(@NLconstraint($m, $F <= 4)))
       end # module HoldBug
WARNING: replacing module HoldBug.

julia> using .HoldBug

julia> using JuMP

julia> m = Model();

julia> @variable(m, x);

julia> @macroexpand HoldBug.@mytest(m, x)
    #= REPL[175]:4 =#
    JuMP._valid_model(m, :m)
        #= /Users/oscar/.julia/dev/JuMP/src/macros.jl:2383 =#
        #= /Users/oscar/.julia/dev/JuMP/src/macros.jl:2384 =#
            #= /Users/oscar/.julia/dev/JuMP/src/macros.jl:2377 =#
                #= /Users/oscar/.julia/dev/JuMP/src/macros.jl:1846 =#
                var"#73###323" = JuMP.Expr(:call, :<=, x, 4)
            #= /Users/oscar/.julia/dev/JuMP/src/macros.jl:2378 =#
            JuMP.add_nonlinear_constraint(m, var"#73###323")

julia> HoldBug.@mytest(m, x)
x - 4.0 ≤ 0

What are you trying to achieve? You should consider instead the raw expression input: Nonlinear Modeling · JuMP

I’m updating the Complementarity package, this piece of code is from the MPEC portion of the module.

Right now the package recursively escapes the expression F, so for example if F = 3*x-y then inside of the macro you get something like

3*esc(x) - esc(y)

rather than


I’ll experiment with add_nonlinear_constraint, but I’ve tried this in the past and it seems to be a similar issue, where the module hangs onto the variable.

Thanks for taking a look at it

Ah. This is pretty non-trivial. We changed quite a lot. The complementarity package is also really old. It’s almost worth using it as inspiration for a rewrite, rather than trying to minimally modify the code.

Good to know. This is actually the last piece to have the code, at least, run. It’s also a good exercise to learn more Julia.

Thanks again for the advice.

1 Like