# Strategy to manage two similar macros which define functions

**URL:** <https://discourse.julialang.org/t/strategy-to-manage-two-similar-macros-which-define-functions/22380>\
**Category:** General Usage\
**Tags:** macros\
**Created:** [March 26, 2019, 10:24pm UTC](https://discourse.julialang.org/t/strategy-to-manage-two-similar-macros-which-define-functions/22380 "2019-03-26T22:24:07Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![giordano](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giordano/32/2166_2.png) [@giordano](https://discourse.julialang.org/u/giordano)\
**Post date:** [March 26, 2019, 10:24pm UTC](https://discourse.julialang.org/t/strategy-to-manage-two-similar-macros-which-define-functions/22380/1 "2019-03-26T22:24:07Z")

</div>

I have two long macros that are almost equal, apart from a few lines:

```julia
macro m1(#= args of m1... =#)
    # set some variables in m1 and m2 before returning the expression...
    # define some other variables only in m1...
    quote
        # first part of the body in common to m1 and m2...
        # this is only in m1...
        # second part in common to m1 and m2...
    end
end

macro m2(#= args of m2... =#)
    # set some variables in m1 and m2 before returning the expression...
    quote
        # first part of the body in common to m1 and m2...
        # second part in common to m1 and m2...
    end
end

```

What’s the best strategy to manage this code and reduce code duplication? I guess I should define functions working on expressions, but I don’t really know how to do that in practice, also because given how `@m1` is defined I’d need to concatenate multiple `Expr` and I have no idea how this works.

For the record, the real code I’d like to simplify and make more maintainable is at [PhysicalConstants.jl/PhysicalConstants.jl at 144d5dcc75f213a4c28c3c67148ac3632cf8c766 · JuliaPhysics/PhysicalConstants.jl · GitHub](https://github.com/JuliaPhysics/PhysicalConstants.jl/blob/144d5dcc75f213a4c28c3c67148ac3632cf8c766/src/PhysicalConstants.jl#L13-L127)

---

<div class="post-metadata">

**Author:** ![yha](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yha/32/3502_2.png) [@yha](https://discourse.julialang.org/u/yha)\
**Post date:** [March 26, 2019, 10:35pm UTC](https://discourse.julialang.org/t/strategy-to-manage-two-similar-macros-which-define-functions/22380/2 "2019-03-26T22:35:51Z")

</div>

> [@giordano](#):
>
> I’d need to concatenate multiple `Expr` and I have no idea how this works.

Do you mean something like this?

```julia
julia> e1 = :(a=1);
julia> e2 = :(b=2);
julia> quote
           $e1
           $e2
       end
quote
    #= REPL[7]:2 =#
    a = 1
    #= REPL[7]:3 =#
    b = 2
end

```

---

<div class="post-metadata">

**Author:** ![giordano](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giordano/32/2166_2.png) [@giordano](https://discourse.julialang.org/u/giordano)\
**Post date:** [March 26, 2019, 11:03pm UTC](https://discourse.julialang.org/t/strategy-to-manage-two-similar-macros-which-define-functions/22380/3 "2019-03-26T23:03:35Z")

</div>

So concatenating expressions is just putting expressions within a `quote` environment, this is great.

I thought I tried something like previously, but apparently I didn’t.

---

<div class="post-metadata">

**Author:** ![giordano](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giordano/32/2166_2.png) [@giordano](https://discourse.julialang.org/u/giordano)\
**Post date:** [March 27, 2019, 12:02am UTC](https://discourse.julialang.org/t/strategy-to-manage-two-similar-macros-which-define-functions/22380/4 "2019-03-27T00:02:57Z")

</div>

> [@giordano](#):
>
> I thought I tried something like previously, but apparently I didn’t.

Well, I’m pretty sure that I did try. In fact now I’m struggling again with the same issue I had before: function definitions (now I remember).

Basically, I have something like this:

```julia
function foo end

macro m1(val)
    eval = esc(val)
    quote
        Main.foo() = $eval
    end
end

```

and I can do

```julia
julia> @m1 5

julia> foo()
5

julia> @m1 4.9

julia> foo()
4.9

```

However, if I try to move the returned expression of the macro to a function, it doesn’t work any more:

```julia
function foo end

function _m2(eval)
    quote
        Main.foo() = $eval
    end
end

macro m2(val)
    eval = esc(val)
    quote
        _m2($eval)
    end
end

```

in the REPL:

```julia
julia> include("/tmp/foo.jl")
@m2 (macro with 1 method)

julia> @m2 5
quote
    #= /tmp/foo.jl:5 =#
    Main.foo() = begin
            #= /tmp/foo.jl:5 =#
            5
        end
end

julia> foo()
ERROR: MethodError: no method matching foo()
Stacktrace:
 [1] top-level scope at none:0

```

---

<div class="post-metadata">

**Author:** ![yha](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yha/32/3502_2.png) [@yha](https://discourse.julialang.org/u/yha)\
**Post date:** [March 27, 2019, 1:12am UTC](https://discourse.julialang.org/t/strategy-to-manage-two-similar-macros-which-define-functions/22380/5 "2019-03-27T01:12:47Z")

</div>

Your `_m2` function already returns an expression, and the macro unnecessarily quotes it into another expression. You just need

```julia
macro m2(val)
    _m2(esc(val))
end

```

If you want to concatenate two such expressions, you can do somthing like

```julia
macro m2(val)
    quote
        $(_m1(esc(val)))
        $(_m2(esc(val)))
    end
end

```

---

<div class="post-metadata">

**Author:** ![giordano](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giordano/32/2166_2.png) [@giordano](https://discourse.julialang.org/u/giordano)\
**Post date:** [March 27, 2019, 1:52am UTC](https://discourse.julialang.org/t/strategy-to-manage-two-similar-macros-which-define-functions/22380/6 "2019-03-27T01:52:02Z")

</div>

Right, this makes sense and works, thank you so much!

I’m almost done. If I’d like to move also the part before the returned expression to a function, I’d have to do that? Should the function return an expression that has to be `@eval`ed in the macro?

---

<div class="post-metadata">

**Author:** ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)\
**Post date:** [March 27, 2019, 3:43am UTC](https://discourse.julialang.org/t/strategy-to-manage-two-similar-macros-which-define-functions/22380/7 "2019-03-27T03:43:41Z")

</div>

> [@giordano](#):
>
> Should the function return an expression that has to be `@eval` ed in the macro?

No, you should never need to call `@eval` or `eval()` within a macro. Your macro should just call the function returning an expression, no further action needed.

For example:

```julia
julia> function make_expr()
         return :(2 + 2)
       end
make_expr (generic function with 1 method)

julia> macro foo()
         return make_expr()
       end
@foo (macro with 1 method)

julia> @macroexpand @foo()
:(2 + 2)

julia> @foo()
4

```

---

<div class="post-metadata">

**Author:** ![giordano](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giordano/32/2166_2.png) [@giordano](https://discourse.julialang.org/u/giordano)\
**Post date:** [March 27, 2019, 6:24am UTC](https://discourse.julialang.org/t/strategy-to-manage-two-similar-macros-which-define-functions/22380/8 "2019-03-27T06:24:15Z")

</div>

> [@rdeits](#):
>
> Your macro should just call the function returning an expression, no further action needed.

I asked about what is _before_ the returned expression, the “preamble” (is there a specific term to identify this part of the macro?), where I set some variables that will be used within the returned expression.

---

<div class="post-metadata">

**Author:** ![ffevotte](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ffevotte/32/6587_2.png) [@ffevotte](https://discourse.julialang.org/u/ffevotte)\
**Post date:** [March 27, 2019, 8:16am UTC](https://discourse.julialang.org/t/strategy-to-manage-two-similar-macros-which-define-functions/22380/9 "2019-03-27T08:16:26Z")

</div>

In this part you could use “standard” (i.e. not macro-specific) code factoring techniques : regular functions taking some arguments and returning the set of values which you want to use in the remaining part of your macro.

Maybe something like this ?

```julia
common_vars() = (1, 2)
m1_vars() = 3

common_code(v1, v2, e) = quote
    println($v1, $v2, $e)
end

m1_code(v1, v2, v3, e) = quote
    sum(($v1, $v2, $v3, $e))
end

macro m1(expr)
    var1, var2 = common_vars()
    var3 = m1_vars()
    quote
        $(common_code(var1, var2, esc(expr)))
        $(m1_code(var1, var2, var3, esc(expr)))
    end
end

```

```julia
julia> @macroexpand @m1 x
quote
    #= REPL[5]:5 =#
    begin
        #= REPL[3]:2 =#
        (Main.println)(1, 2, x)
    end
    #= REPL[5]:6 =#
    begin
        #= REPL[4]:2 =#
        (Main.sum)((1, 2, 3, x))
    end
end

julia> let x = 4
           @m1 x
       end
124
10

```

---

<div class="post-metadata">

**Author:** ![giordano](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giordano/32/2166_2.png) [@giordano](https://discourse.julialang.org/u/giordano)\
**Post date:** [March 27, 2019, 10:36am UTC](https://discourse.julialang.org/t/strategy-to-manage-two-similar-macros-which-define-functions/22380/10 "2019-03-27T10:36:34Z")

</div>

> [@ffevotte](#):
>
> In this part you could use “standard” (i.e. not macro-specific) code factoring techniques : regular functions taking some arguments and returning the set of values which you want to use in the remaining part of your macro.

Well, that was super easy, shame on me ☹ Thanks a lot!

For reference, I’ve implemented the suggestions in this thread in this PR: [Improve maintainability of macros by giordano · Pull Request #8 · JuliaPhysics/PhysicalConstants.jl · GitHub](https://github.com/JuliaPhysics/PhysicalConstants.jl/pull/8)
