# Extending JuMP.@constraint macro: misunderstanding scope?

**URL:** <https://discourse.julialang.org/t/extending-jump-constraint-macro-misunderstanding-scope/43046>\
**Category:** Optimization (Mathematical)\
**Tags:** question, macros\
**Created:** [July 14, 2020, 1:47pm UTC](https://discourse.julialang.org/t/extending-jump-constraint-macro-misunderstanding-scope/43046 "2020-07-14T13:47:01Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![gobs](https://avatars.discourse-cdn.com/v4/letter/g/bc8723/32.png) [@gobs](https://discourse.julialang.org/u/gobs)\
**Post date:** [July 14, 2020, 1:47pm UTC](https://discourse.julialang.org/t/extending-jump-constraint-macro-misunderstanding-scope/43046/1 "2020-07-14T13:47:01Z")

</div>

I’ve been toying with the idea of extending the `JuMP.@constraint` macro to make my code somewhat more concise. Here’s an example of what I currently do:

```julia
con1 = @constraint(gep.model, [i=1:10], x[i] >= 0) # Make an anonymous constraint
gep.model.ext[:constraints][:con1] = con1 # Save it to dict

```

`gep` is a custom type I have which has a field `model::JuMP.Model`.

What I would like to do is extend the macro so that the above two lines are done in just one:

```julia
@constraint(gep, con1[i=1:10], x[i] >= 0) # Make and save constraint

```

I came up with the following (the function is defined within the module which also exports the `gep` type):

```julia
macro constraint(args...)
    if typeof(eval(args[1])) <: GenerationExpansionPlanningModel
		gep = eval(args[1])
		args[1] = :(gep.model)
        con = _constraint_macro(
			gep.model, args[2:end], :constraint, JuMP.parse_constraint_expr
		)
		# save the constraint to GEP here
    else
    	_constraint_macro(args, :constraint, JuMP.parse_constraint_expr)
    end
end

```

On the line where I check `typeof(eval(args[1]))` I get the following error:

```julia
ERROR: LoadError: UndefVarError: gep not defined

```

This error is thrown by Revise, so I’m supposing it’s a syntactical error.

I understood that `eval(args[1])` would evaluate `gep` in the global scope where it is indeed defined, so I don’t understand why this doesn’t work.

That being said I’m starting to realise that this is probably not worth it, but I’m still intrigued as to why this doesn’t work.

---

<div class="post-metadata">

**Author:** ![odow](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/odow/32/28685_2.png) [@odow](https://discourse.julialang.org/u/odow)\
**Post date:** [July 14, 2020, 2:31pm UTC](https://discourse.julialang.org/t/extending-jump-constraint-macro-misunderstanding-scope/43046/2 "2020-07-14T14:31:26Z")

</div>

Macros are nontrivial to write. You should thoroughly read all of the documentation. [Metaprogramming · The Julia Language](https://docs.julialang.org/en/v1/manual/metaprogramming/#)

In particular, using `eval` in a macro is a clear sign that the approach is wrong. Macros should basically take an expression and return a new expression _based on the syntax_, not the type. They should never evaluate the actual values of the input arguments.

So that means you can’t do things like `if typeof(x) :< Foo`.

> That being said I’m starting to realise that this is probably not worth it

It’s probably easier to overload `Base.setindex!`on `gep` so you could go `gep[:con1] = @constraint(...)`.

---

<div class="post-metadata">

**Author:** ![gobs](https://avatars.discourse-cdn.com/v4/letter/g/bc8723/32.png) [@gobs](https://discourse.julialang.org/u/gobs)\
**Post date:** [July 15, 2020, 8:11am UTC](https://discourse.julialang.org/t/extending-jump-constraint-macro-misunderstanding-scope/43046/3 "2020-07-15T08:11:53Z")

</div>

Makes sense, I think I’ll hold off from messing around with macros for a while. Thanks!
