# Avoiding eval() - struggling with correct macro syntax

**URL:** <https://discourse.julialang.org/t/avoiding-eval-struggling-with-correct-macro-syntax/70665>\
**Category:** General Usage\
**Tags:** question, macros\
**Created:** [October 30, 2021, 3:53pm UTC](https://discourse.julialang.org/t/avoiding-eval-struggling-with-correct-macro-syntax/70665 "2021-10-30T15:53:19Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![hhaensel](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hhaensel/32/1207_2.png) [@hhaensel](https://discourse.julialang.org/u/hhaensel)\
**Post date:** [October 30, 2021, 3:53pm UTC](https://discourse.julialang.org/t/avoiding-eval-struggling-with-correct-macro-syntax/70665/1 "2021-10-30T15:53:19Z")

</div>

I’m again struggling with correct macro syntax. I have a macro that is doing it’s job as required but relies on `eval()`, which I understand is not ideal.  
The macro should insert fields of an existing `struct` into a new `struct` that is constructed with `Base.@kwdef`. For testing purposes, I rely on the `@kwredef` macro from  
`RedefStructs`.

```julia
using RedefStructs

macro mixin(expr)
    x = eval(expr)
    T = typeof(x)
    values = [getfield(x, f) for f in fieldnames(T)]

    output = Expr(:block)
    for (f, type, v) in zip(fieldnames(T), fieldtypes(T), values)
        push!(output.args, :($(esc(f))::$type = $v) )
    end
    
    :($output)
end

@kwredef mutable struct TabMixin
    tab::String = "mail"
    animate::Bool = false
end

@kwredef mutable struct Example
    name::String = "Me"
    button::Bool = true

    @mixin TabMixin()
end

ex = Example()
propertynames(ex)

```

I tried to move all into the `quote` part, but I failed…

```julia
macro mixin(expr)
    quote
        local x = $expr
        local T = typeof(x)
        local values = [Stipple.Observables.to_value(getfield(x, f)) for f in fieldnames(T)]

        local output = Expr(:block)
        for (f, type, v) in zip(fieldnames(T), fieldtypes(T), values)
            push!(output.args, :( ($(esc(f)))::$type = $v) )
        end
        
        output
    end
end

```

Can anyone help me here?

---

<div class="post-metadata">

**Author:** ![mauro3](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mauro3/32/292_2.png) [@mauro3](https://discourse.julialang.org/u/mauro3)\
**Post date:** [October 30, 2021, 8:14pm UTC](https://discourse.julialang.org/t/avoiding-eval-struggling-with-correct-macro-syntax/70665/2 "2021-10-30T20:14:52Z")

</div>

I don’t think this can work without the `eval` because the only info the macro gets is `:TabMixin` which is just a Symbol and does not contain any information on the type-def which used that same symbol. Going beyond that you’d need something like a generated type (akin to a generated function) which does not exist.

One possibility would be if you define a custom macro upon definition of `TableMixin` (via decorating it with some other macro), this would mean though that you can only mixin structs which were created thus. Would look something like

```julia
@mixinable struct TabMixin
  a
  b
end
# -> this would, besided the typedef create a macro, say @mixin_TabMixin
struct Example
  name
  button
  @mixin_TabMixin
end

```

This is a similar to the `@unpack_MyType` macro that Parameters.jl’s `@with_kw` macro creates. Maybe you can find inspiration there.

---

<div class="post-metadata">

**Author:** ![WschW](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/wschw/32/6575_2.png) [@WschW](https://discourse.julialang.org/u/WschW)\
**Post date:** [October 30, 2021, 8:33pm UTC](https://discourse.julialang.org/t/avoiding-eval-struggling-with-correct-macro-syntax/70665/3 "2021-10-30T20:33:15Z")

</div>

you can use `getfield( __module__ , expr)` if expr is the name of an unqualified nonparametric type.

If expr can be a parametric type or a qualified type then its a bit more work but still feasible.

Note that this assumes `@mixin TabMixin` instead of `@mixin TabMixin()`

---

<div class="post-metadata">

**Author:** ![hhaensel](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hhaensel/32/1207_2.png) [@hhaensel](https://discourse.julialang.org/u/hhaensel)\
**Post date:** [September 12, 2022, 10:05pm UTC](https://discourse.julialang.org/t/avoiding-eval-struggling-with-correct-macro-syntax/70665/4 "2022-09-12T22:05:25Z")

</div>

Thank you all for your comments. I took me a while to digest and to further work on this.  
Finally I succeeded to build at least a version that can handle evaluation at the calling scope, which I previously didn’t know how to achieve.  
Today I found out that @mauro3 already pointed me in the right direction with ` __module__ ` bit I didn’t get it at that time.  
This is what I ended up with:

```julia
macro mixin(expr, prefix = "", postfix = "")
  if hasproperty(expr, :head) && expr.head == :(::)
      prefix = string(expr.args[1])
      expr = expr.args[2]
  end

  x = Core.eval( __module__ , expr)
  pre = Core.eval( __module__ , prefix)
  post = Core.eval( __module__ , postfix)

  T = x isa DataType ? x : typeof(x)
  mix = x isa DataType ? x() : x
  values = getfield.(Ref(mix), fieldnames(T))
  output = quote end
  for (f, type, v) in zip(Symbol.(pre, fieldnames(T), post), fieldtypes(T), values)
      push!(output.args, :($f::$type = Stipple._deepcopy($v)) )
  end

  esc(:($output))
end

```
