# Julian way to implement structs with different "defaults"?

**URL:** <https://discourse.julialang.org/t/julian-way-to-implement-structs-with-different-defaults/128046>\
**Category:** General Usage\
**Created:** [April 14, 2025, 7:09am UTC](https://discourse.julialang.org/t/julian-way-to-implement-structs-with-different-defaults/128046 "2025-04-14T07:09:03Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![sylvaticus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sylvaticus/32/203883_2.png) [@sylvaticus](https://discourse.julialang.org/u/sylvaticus)\
**Post date:** [April 14, 2025, 7:09am UTC](https://discourse.julialang.org/t/julian-way-to-implement-structs-with-different-defaults/128046/1 "2025-04-14T07:09:03Z")

</div>

Which could be a “julian” way to implement multiple struct defaults?

Like:

```julia
abstract type Parameters end

Base.@kwdef struct ParametersDefault1 <: Parameters
    x = 5
    y = [1,2,3]
    w = 10
    z = x .+ y 
end

Base.@kwdef struct ParametersDefault2 <: Parameters
    x = 5
    y = [10,20,30]
    w = 10
    z = x .+ (2 .* y) 
end

a = ParametersDefault1(x=1)
b = ParametersDefault2(x=1)

```

Where the names and types of the fields would be the same between the various “defaults”.  
In my case, performances are not much of a concern, as most of the time is then spent in Ipopt.

---

<div class="post-metadata">

**Author:** ![sylvaticus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sylvaticus/32/203883_2.png) [@sylvaticus](https://discourse.julialang.org/u/sylvaticus)\
**Post date:** [April 14, 2025, 7:40am UTC](https://discourse.julialang.org/t/julian-way-to-implement-structs-with-different-defaults/128046/2 "2025-04-14T07:40:13Z")

</div>

Perhaps just using different external constructors, altought I still need to explicitly retype the unchanged parameters that are part of other computed defaults:

```julia
Base.@kwdef struct Par
    x = 5
    y = [1,2,3]
    w = 10
    z = x .+ y 
end
function ParDefault1(;kwargs...)
    p = Par(;kwargs...) 
    return p
end
function ParDefault2(;
    x = 5,
    y = [10,20,30],
    z = x .+ (2 .* y) ,
    kwargs...)
    p = Par(;x=x,y=y,z=z,kwargs...) 
    return p
end
c = ParDefault1(x=1)
d = ParDefault2(x=1)

```

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [April 14, 2025, 11:58am UTC](https://discourse.julialang.org/t/julian-way-to-implement-structs-with-different-defaults/128046/3 "2025-04-14T11:58:24Z")

</div>

What I think is not very “julian” there is the fact that `ParDefaults1` (or `2`) do not return an instance of the `ParDefaults1` type. In this sense the first option is more appropriate.

On the other side, another option is to use a function and types only for dispatch, like:

```julia
struct ParDefaults1 end 
struct ParDefaults2 end

function set_parameters(::Type{ParDefaults1}; kargs...)
     return Par(...)
end function

function set_parameters(::Type{ParDefaults2}; kargs...) 
    return Par(...)
end

pars = set_parameters(ParDefaults1; x=1)

```

---

<div class="post-metadata">

**Author:** ![sylvaticus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sylvaticus/32/203883_2.png) [@sylvaticus](https://discourse.julialang.org/u/sylvaticus)\
**Post date:** [April 14, 2025, 12:10pm UTC](https://discourse.julialang.org/t/julian-way-to-implement-structs-with-different-defaults/128046/4 "2025-04-14T12:10:16Z")

</div>

Thank you. Your solution aside the “same name / dispatch on type” is very similar to my first one.  
I am however left with the fact I still need to type `p = Par(;x=x,y=y,z=z,kwargs...)` where in my real case x, y and z are hundreds (and so are the parameters that don’t change, the “w” in the example).. is there a way I can avoid to type them in the `Par` constructor ?

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [April 14, 2025, 12:30pm UTC](https://discourse.julialang.org/t/julian-way-to-implement-structs-with-different-defaults/128046/5 "2025-04-14T12:30:51Z")

</div>

I there is where the `@kwdef` enters, as you are using it. I’m not sure if I get if there’s another problem there.

If `x,y,z...` are hundreds I would guess they are probably better grouped in a vector, I imagine.

---

<div class="post-metadata">

**Author:** ![sylvaticus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sylvaticus/32/203883_2.png) [@sylvaticus](https://discourse.julialang.org/u/sylvaticus)\
**Post date:** [April 14, 2025, 12:38pm UTC](https://discourse.julialang.org/t/julian-way-to-implement-structs-with-different-defaults/128046/6 "2025-04-14T12:38:07Z")

</div>

The whole idea is to have a struct where I have the same fields but different “defaults” where then users can change something punctual (a few parameters) relative to these “defaults”.

I am fine with your solution, I just need to find now a way to “automatically” get the keyword arguments of a function.

For example, in:

```julia
function foo(;
    x = 5,
    y = [10,20,30],
    z = x .+ (2 .* y) ,
    kwargs...)
    p = printme(;x=x,y=y,z=z,kwargs...) 
    return p
end
function printme(;kwargs...)
    for (k,v) in kwargs
        println("$k: $v")
    end
end
foo(;x=10, a=1,b="a")

```

How to avoid typing “x=x,y=y,z=z” ? Is there a macro that provides the keyword arguments (used or not) of a function ?

I can see this [old thread](https://discourse.julialang.org/t/get-the-argument-names-of-an-function/32902/3), but here I need it _inside_ the function itself, so using that method would lead likely to infinite recursion…

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [April 14, 2025, 1:10pm UTC](https://discourse.julialang.org/t/julian-way-to-implement-structs-with-different-defaults/128046/7 "2025-04-14T13:10:21Z")

</div>

I’ve done something like this before:

```julia-repl
julia> function set_args(;args...)
           def_args = Dict(
               :x => 1,
               :y => 2,
           )
           for (key, val) in args
               if haskey(def_args, key)
                   def_args[key] = val
               else
                   error("arg $key no found")
               end
           end
           return def_args
       end
       _foo(args...) = println(args...) # internal
       foo(;kargs...) = _foo(set_args(;kargs...)...) # API
foo (generic function with 3 methods)

julia> foo(;x=10)
:y => 2:x => 10

julia> foo(;z=10)
ERROR: arg z no found

```

---

<div class="post-metadata">

**Author:** ![sylvaticus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sylvaticus/32/203883_2.png) [@sylvaticus](https://discourse.julialang.org/u/sylvaticus)\
**Post date:** [April 14, 2025, 1:25pm UTC](https://discourse.julialang.org/t/julian-way-to-implement-structs-with-different-defaults/128046/8 "2025-04-14T13:25:34Z")

</div>

Thank you again. Yes, I saw the idea to using a Dict, but in my case(as in the example posted) I have some computed args that depend on the other args (the user can redefine the raw args or the way the computed ones, the one used in the model, are made), and basic dicts don’t work in this case.

---

<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:** [April 14, 2025, 1:36pm UTC](https://discourse.julialang.org/t/julian-way-to-implement-structs-with-different-defaults/128046/9 "2025-04-14T13:36:17Z")

</div>

How about the following? Just use one struct and use two possible functions to construct it, each of which have default values for all arguments?

```julia
abstract type Parameters end

struct ParameterType{X,Y,W,Z} <: Parameters
    x::X
    y::Y
    w::W
    z::Z
end

ParametersDefault1(; x = 5, y = [1,2,3], w = 10, z = x .+ y) = ParameterType(x, y, w, z)
ParametersDefault2(; x = 5, y = [10,20,30], w = 10, z = x .+ (2 .* y)) = ParameterType(x, y, w, z)

a = ParametersDefault1(x=1)
b = ParametersDefault2(x=1)
display(a)
display(b)

```

---

<div class="post-metadata">

**Author:** ![yvikhlya](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yvikhlya/32/3753_2.png) [@yvikhlya](https://discourse.julialang.org/u/yvikhlya)\
**Post date:** [April 14, 2025, 1:42pm UTC](https://discourse.julialang.org/t/julian-way-to-implement-structs-with-different-defaults/128046/10 "2025-04-14T13:42:28Z")

</div>

> [@sylvaticus](#):
>
> Is there a macro that provides the keyword arguments (used or not) of a function ?

Keyword arguments is just a named tuple, you can splat it i.e.

```julia
kwargs=(k1=v1,k2=v2,k3=v3)
f(;kwargs...)

```

---

<div class="post-metadata">

**Author:** ![roflmaostc](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/roflmaostc/32/30123_2.png) [@roflmaostc](https://discourse.julialang.org/u/roflmaostc)\
**Post date:** [April 14, 2025, 2:04pm UTC](https://discourse.julialang.org/t/julian-way-to-implement-structs-with-different-defaults/128046/11 "2025-04-14T14:04:57Z")

</div>

Also not quite what you want, but also have a look at

> **[GitHub - mauro3/Parameters.jl: Types with default field values, keyword...](https://github.com/mauro3/Parameters.jl)**
>
> Types with default field values, keyword constructors and (un-)pack macros

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [April 14, 2025, 2:38pm UTC](https://discourse.julialang.org/t/julian-way-to-implement-structs-with-different-defaults/128046/12 "2025-04-14T14:38:35Z")

</div>

> [@sylvaticus](#):
>
> How to avoid typing “x=x,y=y,z=z” ?

FWIW, you can type simply `foo(;x, y, z, kargs...)` to propagate the kargs `x,y,z` of the input. Appart from that I do not see how to simplify further from what `@kwdef` gives you.

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [April 14, 2025, 4:59pm UTC](https://discourse.julialang.org/t/julian-way-to-implement-structs-with-different-defaults/128046/13 "2025-04-14T16:59:25Z")

</div>

What about providing the two sets of default kwargs as namedtuples for the user to refer to?  
Definition:

```julia
@kwdef struct MyParameters
...
end

MyDefaults1 = (x=5, y=...)
MyDefaults2 = (x=10, y=...)

```

Usage:

```julia
MyParameters(; MyDefaults1..., x=1)
MyParameters(; MyDefaults2..., x=1)

```

Seems the most straightforward imo.

---

<div class="post-metadata">

**Author:** ![sylvaticus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sylvaticus/32/203883_2.png) [@sylvaticus](https://discourse.julialang.org/u/sylvaticus)\
**Post date:** [April 15, 2025, 7:11am UTC](https://discourse.julialang.org/t/julian-way-to-implement-structs-with-different-defaults/128046/14 "2025-04-15T07:11:44Z")

</div>

> [@aplavin](#):
>
> ```julia-auto
> MyParameters(; MyDefaults1..., x=1)
> MyParameters(; MyDefaults2..., x=1)
> 
> ```

Nice, I didn’t know that Julia would not complain about “repeated” keyword argument. I still however have the issue of loosing the possibility to compute argument values on the fly based on other arguments, i.e.:

```julia
@kwdef struct MyParameters
    x = 1
    y = 2
    z = x+y
end
    
MyDefaults1 = (x=10, y=20)
MyDefaults2 = (x=1,y=200,z=x+2*y) # This doesn't work

MyParameters(; MyDefaults1...,x=1000,z=3000) # Here Julia doesn't complain about double x keyword and takes 1000

```

---

<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:** [April 15, 2025, 7:39am UTC](https://discourse.julialang.org/t/julian-way-to-implement-structs-with-different-defaults/128046/15 "2025-04-15T07:39:02Z")

</div>

I’m not sure I’m proud of this variation but it might satisfy your requirements.

```julia
@kwdef struct MyParameters
    x = 1
    y = 2
    z = x+y
end

my_defaults1(; x=10, y=20) = Base.@locals()
my_defaults2(; x=1, y=200, z=x+2*y) = Base.@locals()

```

Now you can do

```julia
julia> MyParameters(; my_defaults1()...)
MyParameters(10, 20, 30)

julia> MyParameters(; my_defaults1()..., x=1000, z=3000)
MyParameters(1000, 20, 3000)

julia> MyParameters(; my_defaults2(x=1)...)
MyParameters(1, 200, 401)

```

---

<div class="post-metadata">

**Author:** ![sylvaticus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sylvaticus/32/203883_2.png) [@sylvaticus](https://discourse.julialang.org/u/sylvaticus)\
**Post date:** [April 15, 2025, 7:43am UTC](https://discourse.julialang.org/t/julian-way-to-implement-structs-with-different-defaults/128046/16 "2025-04-15T07:43:00Z")

</div>

Thanks, I am going to test it…  
This works, at the cost to use a small external package for the Struct to NamedTouple convertion…

```julia
using NamedTupleTools # for the ntfromstruct() function
@kwdef struct MyParameters
    x = 1
    y = 2
    w = 3
    z = x+y
    o = x*y
end

@kwdef struct MyDefaults1
    x = 10
    y = 20
end

@kwdef struct MyDefaults2
    x=1
    y=200
    z=x+2*y
end

function mydefaults1(;kwargs...)
  return MyParameters(; ntfromstruct(MyDefaults1())...,kwargs...) 
end
function mydefaults2(;kwargs...)
    return MyParameters(; ntfromstruct(MyDefaults2())...,kwargs...) # Here Julia doesn't complain about double x keyword and takes 1000
end

mydefaults1(x=1000,z=3000) # (1000,20,3,3000,20000)
x=1; y=3000; o=x+y;
mydefaults2(;x=1,y=3000, o=x+y) # (1,3000,3,401,3001)

```

---

<div class="post-metadata">

**Author:** ![cshen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cshen/32/217287_2.png) [@cshen](https://discourse.julialang.org/u/cshen)\
**Post date:** [April 15, 2025, 7:43am UTC](https://discourse.julialang.org/t/julian-way-to-implement-structs-with-different-defaults/128046/17 "2025-04-15T07:43:23Z")

</div>

If you have variables in the default that depend on other stuff,  
why not just have a function at that point?

```julia
@kwdef struct MyParameters
    x = 1
    y = 2
    z = x+y
end
    
MyDefaults1 = (x=10, y=20)
MyDefaults2(; x = 1, y = 200) = (x=x, y=y, z=x+2*y)
# you can even chain defaults:
MyDefaults3(; kwargs...) = MyDefaults2(kwargs..., x = 2)

```

EDIT: This is the poor man’s version of Gunnar’s suggestion 😃

---

<div class="post-metadata">

**Author:** ![sylvaticus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sylvaticus/32/203883_2.png) [@sylvaticus](https://discourse.julialang.org/u/sylvaticus)\
**Post date:** [April 15, 2025, 8:00am UTC](https://discourse.julialang.org/t/julian-way-to-implement-structs-with-different-defaults/128046/18 "2025-04-15T08:00:00Z")

</div>

> [@GunnarFarneback](#):
>
> `my_defaults1()...,`

Yes, this works:

```julia
@kwdef struct MyParameters
    x = 1
    y = 2
    w = 3
    z = x+y
    o = x*y
end

my_defaults1(; x=10, y=20) = Base.@locals()
my_defaults2(; x=1, y=200, z=x+2*y) = Base.@locals()

function mydefaults1(;kwargs...)
  return MyParameters(; my_defaults1()...,kwargs...) 
end
function mydefaults2(;kwargs...)
    return MyParameters(; my_defaults2()...,kwargs...) # Here Julia doesn't complain about double x keyword and takes 1000
end

mydefaults1(x=1000,z=3000) # (1000,20,3,3000,20000)
x=1; y=3000; o=x+y;
mydefaults2(;x=1,y=3000, o=x+y) # (1,3000,3,401,3001)

```

Thank you for letting me discover `Base.@locals()`. Your solution creates a dictionary of local variables that are then iterated with the splat operator… Thank you!

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [April 15, 2025, 11:41am UTC](https://discourse.julialang.org/t/julian-way-to-implement-structs-with-different-defaults/128046/19 "2025-04-15T11:41:16Z")

</div>

> [@sylvaticus](#):
>
> `ntfromstruct`

FYI: the more “standard” and popular version of this is ConstructionBase.jl 's `getproperties()`.

---

<div class="post-metadata">

**Author:** ![Raf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raf/32/3383_2.png) [@Raf](https://discourse.julialang.org/u/Raf)\
**Post date:** [April 15, 2025, 1:31pm UTC](https://discourse.julialang.org/t/julian-way-to-implement-structs-with-different-defaults/128046/20 "2025-04-15T13:31:05Z")

</div>

FieldMetadata.jl lets you add multiple columns of arbitrary named metadata to structs, Which you can use `ConstructionBase.setproperties` to update.
