# Check if optional arguments with default values of method are specified

**URL:** <https://discourse.julialang.org/t/check-if-optional-arguments-with-default-values-of-method-are-specified/126295>\
**Category:** New to Julia\
**Created:** [February 25, 2025, 3:11pm UTC](https://discourse.julialang.org/t/check-if-optional-arguments-with-default-values-of-method-are-specified/126295 "2025-02-25T15:11:06Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![JADekker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jadekker/32/210281_2.png) [@JADekker](https://discourse.julialang.org/u/JADekker)\
**Post date:** [February 25, 2025, 3:11pm UTC](https://discourse.julialang.org/t/check-if-optional-arguments-with-default-values-of-method-are-specified/126295/1 "2025-02-25T15:11:06Z")

</div>

Hi, I’m writing some simulation code in which I run simulations for various choices of parameters and save the results to some files, where file-names are generated automatically by collecting the parameter names and values and putting them in a string. However, if there are many parameters, these file names become very long, making visual inspection harder.

As each parameter has a default value in my problem, I want to omit those parameters that take on their default value from the file name, to make the names a bit shorter. This can be achieved by a sequence of `if` statements, but this is not very ergonomical. Is there a way do this automatically, by looping over all arguments that have default values? Here is a MWE

```julia
function Foo(; a = 1, b = "yes", c = true)
    registered_name = ""
    if a != 1
        registered_name *= "a=$a,"
    end
    if b != "yes"
        registered_name *= "b=$b,"
    end
    if c != true
        registered_name *= "c=$c,"
    end
    display(registered_name)

    # Actual stuff happens here, of course
end

Foo()
Foo(a = 2, b = "Yes!")
Foo(c = false)

```

which gives

```julia
""
"a=2,b=Yes!,"
"c=false,"

```

---

<div class="post-metadata">

**Author:** ![kellertuer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kellertuer/32/220707_2.png) [@kellertuer](https://discourse.julialang.org/u/kellertuer)\
**Post date:** [February 25, 2025, 3:26pm UTC](https://discourse.julialang.org/t/check-if-optional-arguments-with-default-values-of-method-are-specified/126295/2 "2025-02-25T15:26:22Z")

</div>

You can write in one line

```julia
registered_name *= ( (c != true) ? "c=$c" : "");

```

Then you at least spare the three-line `if` things – and the bracket on the left can of course also be interpolated and hence put a few things in one line together as well

```julia
registered_name *= "$( (b != "yes") ? "b=$b" : "")$( (c != true) ? "c=$c" : "")";

```

a disadvantage is maybe still that the default appears both in the signature and the test, but well…

---

<div class="post-metadata">

**Author:** ![JADekker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jadekker/32/210281_2.png) [@JADekker](https://discourse.julialang.org/u/JADekker)\
**Post date:** [February 25, 2025, 4:11pm UTC](https://discourse.julialang.org/t/check-if-optional-arguments-with-default-values-of-method-are-specified/126295/3 "2025-02-25T16:11:41Z")

</div>

Thank you, that does save some code length; however, it still requires a lot of manual typing. I was hoping to find a way to do this automatically (at least avoiding the duplication of the default)

---

<div class="post-metadata">

**Author:** ![GHTaarn](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ghtaarn/32/216007_2.png) [@GHTaarn](https://discourse.julialang.org/u/GHTaarn)\
**Post date:** [February 25, 2025, 5:45pm UTC](https://discourse.julialang.org/t/check-if-optional-arguments-with-default-values-of-method-are-specified/126295/4 "2025-02-25T17:45:55Z")

</div>

How about something like:

```julia
const foodefaults = (; a=1, b="hello", c=pi)

function foo(; kwargs...)
    for k in kwargs
        k.second != foodefaults[k.first] && println(k)
    end
    kw = merge(foodefaults, kwargs)
    # use kw in your code here, e.g.:
    println(kw.b ^ round(Int64, kw.a * kw.c))
end

```

This will save you a lot of coding if there are many keywords, but you will have to write `kw.a` every time you formerly wrote `a`.

---

<div class="post-metadata">

**Author:** ![gustaphe](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gustaphe/32/18174_2.png) [@gustaphe](https://discourse.julialang.org/u/gustaphe)\
**Post date:** [February 26, 2025, 6:27am UTC](https://discourse.julialang.org/t/check-if-optional-arguments-with-default-values-of-method-are-specified/126295/5 "2025-02-26T06:27:14Z")

</div>

This smells like meta-programming. Maybe not a good idea, but a fun challenge. I would start something like

```julia
const isexpr = Meta.isexpr

macro capture_changed(fun)
    return esc(_cap_c(fun))
end

function _cap_c(fun)
    isexpr(fun, :function) || error("must be called on a function definition")
    signature = fun.args[1]
    body = fun.args[2]

    newbody = quote
        changed_kwargs = Vector{Pair{Symbol,Any}}()
    end

    if length(signature.args) >= 2 && isexpr(signature.args[2], :parameters)
        kwargs = signature.args[2].args
        for kwarg in kwargs
            k = kwarg.args[1]
            v = kwarg.args[2]
            push!(
                newbody.args,
                :($k == $v || push!(changed_kwargs, $(QuoteNode(k)) => $k)),
            )
        end
    end
    append!(newbody.args, body.args)
    return Expr(:function, signature, newbody)
end

@capture_changed function f(; a=3, b=4)
    println(changed_kwargs)
    return a * b
end

julia> f(; b=5)
Pair{Symbol, Any}[:b => 5]
15

```

~~Then I would get myself to a computer and test it/figure out the order of arguments/mess around with `QuoteNode`s until it worked.~~  
There we go, took a bit more tinkering than I imagined, but this is along the right lines. Just needs to handle type annotations etc.

---

<div class="post-metadata">

**Author:** ![JADekker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jadekker/32/210281_2.png) [@JADekker](https://discourse.julialang.org/u/JADekker)\
**Post date:** [February 26, 2025, 8:35am UTC](https://discourse.julialang.org/t/check-if-optional-arguments-with-default-values-of-method-are-specified/126295/6 "2025-02-26T08:35:13Z")

</div>

> [@gustaphe](#):
>
> ```julia
> const isexpr = Meta.isexpr
> 
> macro capture_changed(fun)
> return esc(_cap_c(fun))
> end
> 
> function _cap_c(fun)
> isexpr(fun, :function) || error("must be called on a function definition")
> signature = fun.args[1]
> body = fun.args[2]
> 
> newbody = quote
> changed_kwargs = Vector{Pair{Symbol,Any}}()
> end
> 
> if length(signature.args) >= 2 && isexpr(signature.args[2], :parameters)
> kwargs = signature.args[2].args
> for kwarg in kwargs
> k = kwarg.args[1]
> v = kwarg.args[2]
> push!(
> newbody.args,
> :($k == $v || push!(changed_kwargs, $(QuoteNode(k)) => $k)),
> )
> end
> end
> append!(newbody.args, body.args)
> return Expr(:function, signature, newbody)
> end
> 
> @capture_changed function f(; a=3, b=4)
> println(changed_kwargs)
> return a * b
> end
> 
> julia> f(; b=5)
> Pair{Symbol, Any}[:b => 5]
> 15
> 
> ```

Thank you, I will study this!

---

<div class="post-metadata">

**Author:** ![JADekker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jadekker/32/210281_2.png) [@JADekker](https://discourse.julialang.org/u/JADekker)\
**Post date:** [February 26, 2025, 8:57am UTC](https://discourse.julialang.org/t/check-if-optional-arguments-with-default-values-of-method-are-specified/126295/7 "2025-02-26T08:57:26Z")

</div>

> [@gustaphe](#):
>
> ```julia
> function _cap_c(fun)
> isexpr(fun, :function) || error("must be called on a function definition")
> signature = fun.args[1]
> body = fun.args[2]
> 
> newbody = quote
> changed_kwargs = Vector{Pair{Symbol,Any}}()
> end
> 
> if length(signature.args) >= 2 && isexpr(signature.args[2], :parameters)
> kwargs = signature.args[2].args
> for kwarg in kwargs
> k = kwarg.args[1]
> v = kwarg.args[2]
> push!(
> newbody.args,
> :($k == $v || push!(changed_kwargs, $(QuoteNode(k)) => $k)),
> )
> end
> end
> append!(newbody.args, body.args)
> return Expr(:function, signature, newbody)
> end
> 
> ```

I have written a helper function to then write these things to a string, which seems to work nicely! Thank you!

```julia
function string_changed(changed_kwargs)
    string_name = ""
    for i in changed_kwargs
        string_name *= "$(String(i.first))=$(i.second),"
    end
    return string_name
end

@capture_changed function f(; a=3, b=4, c=true)
    display(string_changed(changed_kwargs))
    return a * b
end

display(f(a=4, c=false))

```

gives

```julia
"a=4,c=false,"
16

```
