# Writing this inner constructor with a macro

**URL:** <https://discourse.julialang.org/t/writing-this-inner-constructor-with-a-macro/62945>\
**Category:** General Usage\
**Tags:** macros\
**Created:** [June 15, 2021, 12:37pm UTC](https://discourse.julialang.org/t/writing-this-inner-constructor-with-a-macro/62945 "2021-06-15T12:37:32Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![Amval](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/amval/32/6217_2.png) [@Amval](https://discourse.julialang.org/u/Amval)\
**Post date:** [June 15, 2021, 12:37pm UTC](https://discourse.julialang.org/t/writing-this-inner-constructor-with-a-macro/62945/1 "2021-06-15T12:37:32Z")

</div>

Hello,

I am trying to write a macro to reduce some boilerplate. I have some builder method for structs to do some complicated transformations on a dict. I am copypasting something similar to this over and over:

```julia
struct Vehicle
    engine::Engine
    brand::String

    function Vehicle(params::AbstractDict)
        args = build(Vehicle, params)
        if typeof(params) <: Exception
            args
        else
            new(args...)
        end
    end
end

```

and I would like to just do it like this:

```julia
struct Vehicle
    engine::Engine
    brand::String

   @build(Vehicle, params)
end

```

I prefer this to wrapping the whole struct on a macro (seems less explicit and well, I am not even able to write even this simple macro, so…).

I am trying to build this simpler example

```julia
macro build(type, params)
    quote
        function $(esc(type))($(esc(params))::AbstractDict)
            args = build($(esc(type)), $(esc(params)))
            $(esc(Expr(:call, :new, args...)))
        end
    end
end

```

This is the only way I found to call `new`. But then of course `args` is undefined.

Any suggestions or something obvious I am missing?

---

<div class="post-metadata">

**Author:** ![mcabbott](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mcabbott/32/6603_2.png) [@mcabbott](https://discourse.julialang.org/u/mcabbott)\
**Post date:** [June 15, 2021, 1:31pm UTC](https://discourse.julialang.org/t/writing-this-inner-constructor-with-a-macro/62945/2 "2021-06-15T13:31:44Z")

</div>

The only thing which needs escaping here is `type`, since that must match the name of the struct. The others, `params` and `args`, are local variables whose names don’t matter; _not_ escaping them means that they cannot clash with e.g. `type`.

The other thing is that you have an `args` (which isn’t defined) where you want `:args`. Often it helps to dump what you’re trying to construct:

```julia
julia> :(new(args...)) |> dump
Expr
  head: Symbol call
  args: Array{Any}((2,))
    1: Symbol new
    2: Expr
      head: Symbol ...
      args: Array{Any}((1,))
        1: Symbol args

julia> Expr(:call, :new, Expr(:(...), :args))
:(new(args...))

julia> macro build(type)
           quote
               function $(esc(type))(params::AbstractDict)
                   args = build($(esc(type)), params)
                   $(Expr(:call, :new, Expr(:(...), :args)))
               end
           end
       end
@build (macro with 1 method)

julia> @macroexpand @build Vehicle
quote
    #= REPL[26]:3 =#
    function Vehicle(var"#30#params"::Main.AbstractDict)
        #= REPL[26]:3 =#
        #= REPL[26]:4 =#
        var"#29#args" = Main.build(Vehicle, var"#30#params")
        #= REPL[26]:5 =#
        Main.new(var"#29#args"...)
    end
end

```

Whether this is a good idea, rather than say making a parametric type, is another question of course.

---

<div class="post-metadata">

**Author:** ![Amval](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/amval/32/6217_2.png) [@Amval](https://discourse.julialang.org/u/Amval)\
**Post date:** [June 15, 2021, 2:16pm UTC](https://discourse.julialang.org/t/writing-this-inner-constructor-with-a-macro/62945/3 "2021-06-15T14:16:36Z")

</div>

Thanks a lot for your answer. Unfortunately, that doesn’t seem to work when used as I intend to:

```julia
struct Example
    stuff::String
    @build(Example, params)
end

julia> Example(Dict(:stuff => "thing"))
# UndefVarError: new not defined

```

> Whether this is a good idea, rather than say making a parametric type, is another question of course.

Well, I am already doing it (with I think good reason), just copypasting the boilerplate constructor over and over is what I want to abstract away. Not sure how a parametric type would help.

EDIT: Simply escaping new works. Again, thanks a lot for your help 🙂  
I think it’s because `new()` can only be called from inside a struct, and therefore needs to be escaped to be in the right context.

```julia
macro build(type, params)
    quote
        function $(esc(type))(params::AbstractDict)
            args = build($(esc(type)), params)
            $(Expr(:call, esc(:new), Expr(:(...), :args)))
        end
    end
end

```
