Custom keyword arguments with metaprogramming

I am trying to recreate the function fun1 using metaprogramming, and fun2 is my attempt but I’m running into errors. How can I do this (or is there a better way to get this done)?

# Arbitrary struct
struct ABC
    A
    B
    C
end

# The function I'm trying to create with meta programming
function fun1(ABC;
    A = ABC.A,
    B = ABC.B,
    C = ABC.C,
)
    return A + B + C
end

# The non-working version
keywords = join(["$field = ABC.$field" for field in fieldnames(ABC)], ",\n")

eval(quote
function fun2(ABC;
    $(keywords),
)
    return A + B + C
end
end)

The errors are

ERROR: syntax: invalid keyword argument syntax ""A = ABC.A,
B = ABC.B,
C = ABC.C"" around REPL[83]:2
Stacktrace:
 [1] top-level scope
   @ none:1
 [2] eval
   @ ./boot.jl:373 [inlined]
 [3] eval(x::Expr)
   @ Base.MainInclude ./client.jl:453
 [4] top-level scope
   @ REPL[83]:1

You don’t want to use strings for this. dump is your friend for figuring out what to build; I’m not sure if there is a more tidy way to build this one, but explicitly calling Expr should let you build anything:

julia> :(f(x; y=1, z=2)) |> dump
Expr
  head: Symbol call
  args: Array{Any}((3,))
    1: Symbol f
    2: Expr
      head: Symbol parameters
      args: Array{Any}((2,))
        1: Expr
          head: Symbol kw
          args: Array{Any}((2,))
            1: Symbol y
            2: Int64 1
        2: Expr
          head: Symbol kw
          args: Array{Any}((2,))
            1: Symbol z
            2: Int64 2
    3: Symbol x

julia> nt = (y=1, z=2);

julia> :(f(x; $(nt...)))  # doesn't work
:(f(x; 1, 2))

julia> :(f(x, $(; nt...)))
:(f(x, (y = 1, z = 2)))

julia> :(f(x; $nt...))
:(f(x; (y = 1, z = 2)...))

julia> kw = Expr(:parameters, Expr(:kw, :y, 1), Expr(:kw, :z, 2));

julia> :(f($kw, x))
:(f(x; y = 1, z = 2))

julia> dump(ans)
2 Likes