# Am I using macros properly to avoid code repetition?

**URL:** <https://discourse.julialang.org/t/am-i-using-macros-properly-to-avoid-code-repetition/135122>\
**Category:** New to Julia\
**Tags:** macros\
**Created:** [January 18, 2026, 11:39am UTC](https://discourse.julialang.org/t/am-i-using-macros-properly-to-avoid-code-repetition/135122 "2026-01-18T11:39:32Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![WalterMadelim](https://avatars.discourse-cdn.com/v4/letter/w/3e96dc/32.png) [@WalterMadelim](https://discourse.julialang.org/u/WalterMadelim)\
**Post date:** [January 18, 2026, 11:39am UTC](https://discourse.julialang.org/t/am-i-using-macros-properly-to-avoid-code-repetition/135122/1 "2026-01-18T11:39:32Z")

</div>

I want to define a macro inside a module `MyAddConstrs`, hoping that I can avoid code repetition therein. The original code is

```julia-auto
module MyAddConstrs
import JuMP

_gen2(model, GD, p, t, s) = JuMP.@expression(model,
    sum(p[t,s,z,g,:u]-p[t,s,z,g,:d] for z=GD.Zone for g=eachindex(GD.N[z]))
)

add(model, t, s, Other, Reserve, Wind, Demand, Load, p, p0, ϖ, ζ) = JuMP.@constraint(model,
    [t=t, s=s],
    _gen(model, Other, Reserve, Wind, Demand, t, s, p, p0, ϖ, ζ) ==
    -_Const(Wind, Load, Demand, t, s)
)
add(model, t, s, Other, Reserve, Wind, Demand, Load, p, p0, ϖ, ζ, δ) = JuMP.@constraint(model,
    [t=t, s=s],
    _gen2(model, Reserve, δ, t, s) +
    _gen(model, Other, Reserve, Wind, Demand, t, s, p, p0, ϖ, ζ) ==
    -_Const(Wind, Load, Demand, t, s)
)

end

```

Seemingly it is complicated. But actually it’s very simple—the second `add` method at the bottom only has one more term at the left-hand-side, compared to the first `add` method (and one more arg `δ`). The `_gen2` is an ordinary function defined as shown.

Now I seek to replace the two `JuMP.@constraint` body with two macro calls, so that the new module reads

```julia-auto
module MyAddConstrs
import JuMP

_gen2(model, GD, p, t, s) = ... # unaltered

macro _m(e) return esc(quote
    JuMP.@constraint(model, [t=t, s=s],
        $e + _gen(model, Other, Reserve, Wind, Demand, t, s, p, p0, ϖ, ζ) ==
        -_Const(Wind, Load, Demand, t, s)
    )
end) end

add(model, t, s, Other, Reserve, Wind, Demand, Load, p, p0, ϖ, ζ) = @_m(JuMP.AffExpr(0))
add(model, t, s, Other, Reserve, Wind, Demand, Load, p, p0, ϖ, ζ, δ) = @_m(_gen2(model, Reserve, δ, t, s))
 
end

```

I wonder if I’m attaining my aim properly. (The final numeric results seem to be identical though)

---

<div class="post-metadata">

**Author:** ![GunnarFarneback](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gunnarfarneback/32/1827_2.png) [@GunnarFarneback](https://discourse.julialang.org/u/GunnarFarneback)\
**Post date:** [January 18, 2026, 12:05pm UTC](https://discourse.julialang.org/t/am-i-using-macros-properly-to-avoid-code-repetition/135122/2 "2026-01-18T12:05:02Z")

</div>

It looks likely to be fine, although I never like trying to reason about how nested macros interact.

If it was my code I would try to reduce the duplication with an optional function argument rather than a macro, something like

```julia-auto
add(model, t, s, Other, Reserve, Wind, Demand, Load, p, p0, ϖ, ζ, δ = nothing) = JuMP.@constraint(model,
    [t=t, s=s],
    _gen(model, Other, Reserve, Wind, Demand, t, s, p, p0, ϖ, ζ, δ) ==
    -_Const(Wind, Load, Demand, t, s)
)

function _gen(model, Other, Reserve, Wind, Demand, t, s, p, p0, ϖ, ζ, δ)
    x = ...
    if !isnothing(δ)
        x += _gen2(model, Reserve, δ, t, s)
    end
    return x
end

```

---

<div class="post-metadata">

**Author:** ![WalterMadelim](https://avatars.discourse-cdn.com/v4/letter/w/3e96dc/32.png) [@WalterMadelim](https://discourse.julialang.org/u/WalterMadelim)\
**Post date:** [January 18, 2026, 12:49pm UTC](https://discourse.julialang.org/t/am-i-using-macros-properly-to-avoid-code-repetition/135122/3 "2026-01-18T12:49:47Z")

</div>

Thanks for the advice.

The main concern about your solution is that you introduced a `if`-branch inside the body of `JuMP.@constraint`, which could _to a certain extent_ be adverse to performance. The other minor concern is that `_gen2(..., ..., ....)` returns a JuMP expression, so the `x += _gen2(...)` is outside of the JuMP’s macro.

These are very JuMP-related performance concerns, which is unrelated to the general idea.

If my macro method works good, I’ll probably use that in practice. That looks nice—as long as I confine those code to be local, inside the module `MyAddConstrs`. And I only call `MyAddConstrs.add` from outside.

---

<div class="post-metadata">

**Author:** ![GunnarFarneback](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gunnarfarneback/32/1827_2.png) [@GunnarFarneback](https://discourse.julialang.org/u/GunnarFarneback)\
**Post date:** [January 18, 2026, 1:54pm UTC](https://discourse.julialang.org/t/am-i-using-macros-properly-to-avoid-code-repetition/135122/4 "2026-01-18T13:54:08Z")

</div>

I won’t try to predict what the JuMP macros do, but in normal functions this kind of if-branch would be eliminated during compilation thanks to method specialization and constant propagation.

---

<div class="post-metadata">

**Author:** ![abraemer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abraemer/32/51403_2.png) [@abraemer](https://discourse.julialang.org/u/abraemer)\
**Post date:** [January 18, 2026, 5:22pm UTC](https://discourse.julialang.org/t/am-i-using-macros-properly-to-avoid-code-repetition/135122/5 "2026-01-18T17:22:41Z")

</div>

General rules of thumbs are:

- If a function can do it, use a function (they compose better, are better to reason about, more extensible…)
- usually macros are not for performance optimization (yes they technically can inline things but you can force that with a `@inline`. If you need very precise control over how something is compiled, use a `@generated` function).

Usually macros are a meant for syntactic transformations usually to provide a better interface to something (see e.g. ModelingToolkit.jl) or when a function would not do (e.g. `@time`).

In your case, I would prefer the function solution of @GunnarFarneback. As long as Julia can infer whether `δ` is nothing the branch will be removed.

---

<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:** [January 18, 2026, 10:49pm UTC](https://discourse.julialang.org/t/am-i-using-macros-properly-to-avoid-code-repetition/135122/6 "2026-01-18T22:49:34Z")

</div>

If your question is “am I using macros properly” the answer is that “mostly you shouldn’t”

[![](https://global.discourse-cdn.com/julialang/original/3X/7/5/759062729d830f12cdfa7374e0be51cc40e42a54.jpeg "Keynote. Professor Steven G. Johnson | JuliaCon 2019") ](https://www.youtube.com/watch?v=mSgXWpvQEHE&t=576s)

Write verbose code that is easy to read. Do not write terse code that is hard to reason about.

---

<div class="post-metadata">

**Author:** ![WalterMadelim](https://avatars.discourse-cdn.com/v4/letter/w/3e96dc/32.png) [@WalterMadelim](https://discourse.julialang.org/u/WalterMadelim)\
**Post date:** [January 19, 2026, 12:56am UTC](https://discourse.julialang.org/t/am-i-using-macros-properly-to-avoid-code-repetition/135122/7 "2026-01-19T00:56:58Z")

</div>

Thanks.

I realized that the compilation ability is strong. My application here is to add a power balance equation across the whole power system with multiple zones and different types of generators. Under your guidance, I revised my module (full-version) as

```julia-auto
module Balance
import ..WindCur, JuMP

_Wind(t, s, GD) = sum(WindCur.UB(GD,t,s,z,g) for z=GD.Zone for g=eachindex(GD.N[z]))
_Load(t, GD) = sum(GD.P[z][t,g] for z=GD.Zone for g=eachindex(GD.N[z]))
_Const(t, s, Wind, Load, Demand) = _Wind(t, s, Wind) - _Load(t, Load) - _Load(t, Demand)

_gen(model, t, s, GD, p) = JuMP.@expression(model, sum(p[t,s,z,g] for z=GD.Zone for g=eachindex(GD.N[z])))
function _gen(model, t, s, Other, Reserve, Wind, Demand, p, p0, ϖ, ζ, δ)
    e = JuMP.@expression(model,
        _gen(model, t, s, Other, p) + _gen(model, t, s, Reserve, p0) +
        sum(ζ[t,s,z,g,:d]-ζ[t,s,z,g,:u] for z=Demand.Zone for g=eachindex(Demand.N[z])) -
        sum(ϖ[t,s,z,g] for z=Wind.Zone for g=eachindex(Wind.N[z]))
    )
    if !isnothing(δ)
        return JuMP.@expression(model, e + # add a redispatch term
            sum(δ[t,s,z,g,:u]-δ[t,s,z,g,:d] for z=Reserve.Zone for g=eachindex(Reserve.N[z]))
        )
    end
    e
end

add(model, t, s, Other, Reserve, Wind, Demand, Load, p, p0, ϖ, ζ, δ=nothing) = JuMP.@constraint(model,
    [t=t, s=s],
    _gen(model, t, s, Other, Reserve, Wind, Demand, p, p0, ϖ, ζ, δ) == -_Const(t, s, Wind, Load, Demand)
)

end

```

I think it’s now both clean in logic and minimal in code space.

> [@abraemer](#):
>
> As long as Julia can infer whether `δ` is nothing the branch will be removed.

I’ve learned. Thanks.

> [@odow](#):
>
> Write verbose code that is easy to read.

Verbose code is not easy to read and check🥲. Real-world physical applications (e.g. power networks) are complicated in nature and I have to spend much time writing and organizing code carefully. (I think my updated version looks good now)
