# Help with macro

**URL:** <https://discourse.julialang.org/t/help-with-macro/429>\
**Category:** General Usage\
**Tags:** question\
**Created:** [November 19, 2016, 10:16am UTC](https://discourse.julialang.org/t/help-with-macro/429 "2016-11-19T10:16:12Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [November 19, 2016, 10:16am UTC](https://discourse.julialang.org/t/help-with-macro/429/1 "2016-11-19T10:16:12Z")

</div>

I am trying to write a macro which would transform

```julia
@enum_and_dict(foo, foodict, "A" => A, "B" => B)

```

to

```julia
@enum foo A B
foodict = Dict("A" => A, "B" => B)

```

I have tried this:

```julia
macro enum_and_dict(enumname, dictvar, pairs...)
    function expr_second(expr)
        @assert expr.head ≡ :(=>) "$expr is not a Pair."
        esc(expr.args[2])
    end
    quote
        @enum($(esc(enumname)), $(map(expr_second, pairs)...))
        $(esc(dictvar)) = Dict($(pairs...))
    end
end

```

and the `Dict` part works fine, but for the first one I get a very complicated expression, and I don’t know why, or how to fix it.

---

<div class="post-metadata">

**Author:** ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)\
**Post date:** [November 19, 2016, 12:55pm UTC](https://discourse.julialang.org/t/help-with-macro/429/2 "2016-11-19T12:55:59Z")

</div>

What do you mean you get a very complicated expression? You mean the expansion result of `@enum` itself? It’s working AFAICT.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [November 19, 2016, 2:14pm UTC](https://discourse.julialang.org/t/help-with-macro/429/3 "2016-11-19T14:14:01Z")

</div>

I see… it also expanded `@enum`. So it is indeed working as expected.

What’s the Julia equivalent of `COMMON-LISP:MACROEXPAND-1`, that would just expand the first level, not recursively?

---

<div class="post-metadata">

**Author:** ![ihnorton](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ihnorton/32/26_2.png) [@ihnorton](https://discourse.julialang.org/u/ihnorton)\
**Post date:** [November 19, 2016, 8:45pm UTC](https://discourse.julialang.org/t/help-with-macro/429/4 "2016-11-19T20:45:02Z")

</div>

> [@Tamas\_Papp](#):
>
> What’s the Julia equivalent of COMMON-LISP:MACROEXPAND-1, that would just expand the first level, not recursively?

I don’t think this exists. If you want to look at the code, see the entrypoint `julia-expand-macros` in `src/macroexpand.scm`.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [November 20, 2016, 8:24am UTC](https://discourse.julialang.org/t/help-with-macro/429/5 "2016-11-20T08:24:29Z")

</div>

Thanks, I opened an issue.

[https://github.com/JuliaLang/julia/issues/19365](https://github.com/JuliaLang/julia/issues/19365)

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [November 20, 2016, 1:16pm UTC](https://discourse.julialang.org/t/help-with-macro/429/6 "2016-11-20T13:16:05Z")

</div>

Using the macro above in another module, I found that is missing an `esc`. A correct MWE is

```julia
module Foo # minimal working example
macro enum_and_Dict(enumname, dictvar, pairs...)
    function expr_second(expr)
        @assert expr.head ≡ :(=>) "$expr is not a Pair."
        esc(expr.args[2])
    end
    quote
        @enum($(esc(enumname)), $(map(expr_second, pairs)...))
        $(esc(dictvar)) = Dict($(map(esc, pairs)...))
    end
end
module Bar # using the macro in a submodule
import ..@enum_and_Dict
@enum_and_Dict(BarEnum, bar_dict, "a"=>a)
end
end

```

**Question** : is it possible to simplify this code, or make it more idiomatic? Style hints are welcome, I am still learning Julia macros.

---

<div class="post-metadata">

**Author:** ![akis](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/akis/32/156_2.png) [@akis](https://discourse.julialang.org/u/akis)\
**Post date:** [November 20, 2016, 6:10pm UTC](https://discourse.julialang.org/t/help-with-macro/429/7 "2016-11-20T18:10:57Z")

</div>

How is:  
`@enum_and_dict(foo, foodict, "A" => A, "B" => B)`  
a worthy improvement over:  
`@enum foo A B; foodict = Dict("A" => A, "B" => B)`  
?

Is there an important gain from the proposed macro, other than making the code resemble LISP (and potentially harder to read by some people)?

> [@Tamas\_Papp](#):
>
> is it possible to simplify this code, or make it more idiomatic?

I think that the idiomatic way would be to take some distance from LISP and not use a macro in this case.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [November 20, 2016, 6:20pm UTC](https://discourse.julialang.org/t/help-with-macro/429/8 "2016-11-20T18:20:47Z")

</div>

In my actual use case, the enums have about 15–25 values, and I have 4+ different enums. Think of something like

```julia
@enum_and_Dict(EmploymentCategories,
               employment_encodings,
               "AA" => unemployed,
               "D2" => disabled_other,
               ... # approx. 20 other lines
               )

```

Enumerating values twice is error prone and tedious. I don’t see any resemblance to LISP in the code above, the goal is to eliminate redundancy. Also, I am not sure how you can do this without macros (but I am interested in suggestions — macros are not the end here, just the means).

---

<div class="post-metadata">

**Author:** ![Ralph\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ralph_smith/32/10344_2.png) [@Ralph\_Smith](https://discourse.julialang.org/u/Ralph_Smith)\
**Post date:** [November 21, 2016, 12:48am UTC](https://discourse.julialang.org/t/help-with-macro/429/9 "2016-11-21T00:48:35Z")

</div>

You don’t need a new macro if you don’t mind starting with symbols (at the risk of annoying akis with somewhat cryptic code):

```julia
module M

function enum_and_dict(d::Dict{String,Symbol},ename)
    ds=([v for (k,v) in d]...)
    @eval @enum $ename $(ds...)
    dnew = Dict(k => getfield(M,v) for (k,v) in d)
end

d1 = Dict("A" => :A, "B" => :B)
d2 = enum_and_dict(d1,:MyEnum)
display(MyEnum)
display(d2)
end

Enum M.MyEnum:
B = 0
A = 1
Dict{String,M.MyEnum} with 2 entries:
  "B" => B
  "A" => A

```

---

<div class="post-metadata">

**Author:** ![akis](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/akis/32/156_2.png) [@akis](https://discourse.julialang.org/u/akis)\
**Post date:** [November 21, 2016, 5:21am UTC](https://discourse.julialang.org/t/help-with-macro/429/10 "2016-11-21T05:21:15Z")

</div>

> [@Tamas\_Papp](#):
>
> I don’t see any resemblance to LISP in the code above

To my eyes, the resemblance is in the mixed arguments inside long parentheses (I may be biased though).

> [@Ralph\_Smith](#):
>
> You don’t need a new macro if you don’t mind starting with symbols (at the risk of annoying akis with somewhat cryptic code)

I don’t mind symbols (they are present eitherway). And not annoyed by `@eval` (definitely less cryptic than the proposed macro). It should be `$(values(d)...)` though.
