# Creating a method dynamically with keyword arguments

**URL:** <https://discourse.julialang.org/t/creating-a-method-dynamically-with-keyword-arguments/110108>\
**Category:** General Usage\
**Tags:** question, metaprogramming\
**Created:** [February 12, 2024, 3:48pm UTC](https://discourse.julialang.org/t/creating-a-method-dynamically-with-keyword-arguments/110108 "2024-02-12T15:48:01Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![Janis\_Erdmanis](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/janis_erdmanis/32/10869_2.png) [@Janis\_Erdmanis](https://discourse.julialang.org/u/Janis_Erdmanis)\
**Post date:** [February 12, 2024, 3:48pm UTC](https://discourse.julialang.org/t/creating-a-method-dynamically-with-keyword-arguments/110108/1 "2024-02-12T15:48:01Z")

</div>

I have a context structure with many fields and want to mutate some by reinitialising, where I could do various validations. I know there is an excellent SetField.jl package, but I have only one structure, and thus, I would like to avoid introducing additional dependencies. Thus I am attempting to construct the following code with an eval:

```julia
struct Context
    a::Int
    b::Int
end

function Context(ctx; a=ctx.a, b=ctx.b)
    return Context(a, b)
end

ctx = Context(2, 4)
new_ctx = Context(ctx, a=3)

```

So far the best I have come up with is using the strings and at the last stage calling `Meta.parse`:

```julia
function_signature = join(["$(f)=ctx.$(f)" for f in fieldnames(Context)], ", ")
function_body = join(["$(f)" for f in fieldnames(Context)], ", ")

body = """
function Context(ctx::Context; $function_signature)
    return Context($function_body)
end
"""

eval(Meta.parse(body))

```

But this did not work out, although the body contains the exact definition I need. I would also much prefer using expressions directly. Can someone help me with this?

---

<div class="post-metadata">

**Author:** ![GunnarFarneback](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gunnarfarneback/32/1827_2.png) [@GunnarFarneback](https://discourse.julialang.org/u/GunnarFarneback)\
**Post date:** [February 12, 2024, 4:06pm UTC](https://discourse.julialang.org/t/creating-a-method-dynamically-with-keyword-arguments/110108/2 "2024-02-12T16:06:10Z")

</div>

Is it time critical? Does it have to involve metaprogramming?

If not I’d try something like

```julia
julia> @kwdef struct Context
           a::Int
           b::Int
       end
Context

julia> function Context(ctx::Context; kwargs...)
           return Context(; merge(Dict(f => getfield(ctx, f) for f in fieldnames(Context)), kwargs)...)
       end
Context

julia> ctx = Context(2, 4)
Context(2, 4)

julia> new_ctx = Context(ctx, a=3)
Context(3, 4)

```

---

<div class="post-metadata">

**Author:** ![Janis\_Erdmanis](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/janis_erdmanis/32/10869_2.png) [@Janis\_Erdmanis](https://discourse.julialang.org/u/Janis_Erdmanis)\
**Post date:** [February 12, 2024, 4:21pm UTC](https://discourse.julialang.org/t/creating-a-method-dynamically-with-keyword-arguments/110108/3 "2024-02-12T16:21:05Z")

</div>

Looks good. Although I would like to see how the metaprpgraming approach would look like.

---

<div class="post-metadata">

**Author:** ![Janis\_Erdmanis](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/janis_erdmanis/32/10869_2.png) [@Janis\_Erdmanis](https://discourse.julialang.org/u/Janis_Erdmanis)\
**Post date:** [February 12, 2024, 5:36pm UTC](https://discourse.julialang.org/t/creating-a-method-dynamically-with-keyword-arguments/110108/4 "2024-02-12T17:36:44Z")

</div>

I made a variation of your approach which does not require to use `@kwdef`:

```julia
struct Context
    a
    b
end

function Context(ctx::Context; kwargs...)
    return Context([get(kwargs, key, getfield(ctx, key)) for key in fieldnames(Context)]...)
end

ctx = Context(2, 3)
Context(ctx; a=4)

```

The problem is however that `Context(ctx; c=4)` does not error. So I also need to add also validation check for `kwargs`.

---

<div class="post-metadata">

**Author:** ![Janis\_Erdmanis](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/janis_erdmanis/32/10869_2.png) [@Janis\_Erdmanis](https://discourse.julialang.org/u/Janis_Erdmanis)\
**Post date:** [February 12, 2024, 6:25pm UTC](https://discourse.julialang.org/t/creating-a-method-dynamically-with-keyword-arguments/110108/5 "2024-02-12T18:25:33Z")

</div>

Solved it

```julia
@eval begin
    function Context(ctx::Context; $([Expr(:kw ,k, :(ctx.$k)) for k in fieldnames(Context)]...))
        return Context($(fieldnames(Context)...))
    end
end

```
