# Struct with partial explicit constructs that init subset of fields

**URL:** <https://discourse.julialang.org/t/struct-with-partial-explicit-constructs-that-init-subset-of-fields/79618>\
**Category:** General Usage\
**Tags:** question, type, data\_structures, struct, constructors\
**Created:** [April 18, 2022, 6:21am UTC](https://discourse.julialang.org/t/struct-with-partial-explicit-constructs-that-init-subset-of-fields/79618 "2022-04-18T06:21:10Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![FireCrumb](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/firecrumb/32/35370_2.png) [@FireCrumb](https://discourse.julialang.org/u/FireCrumb)\
**Post date:** [April 18, 2022, 6:21am UTC](https://discourse.julialang.org/t/struct-with-partial-explicit-constructs-that-init-subset-of-fields/79618/1 "2022-04-18T06:21:10Z")

</div>

Hi, I have a struct with several fields, wherein various scenarios only some of them are filled.  
The total amount of combinations of which fields are filled is too big to have different types for each.

For sake of simplicity, let’s say I have three numeric fields, and I want to be able to construct the struct while providing any two of them:

```julia
struct abc
    a::Int
    b::Int
    c::Int
    abc(a,b)=new(a,b,0)
    abc(b,c)=new(0,b,c)
end

abc1 = abc(a=1, b=2)
abc2 = abc(b=3, c=4)

```

However, this fails, as both constructors are the same:

```julia
MethodError: no method matching abc(; a=1, b=2)
Closest candidates are:
  abc(::Any, ::Any) at In[3]:6 got unsupported keyword arguments "a", "b"

```

Note that _not every combination_ of fields is acceptable, so I can’t just have a single constructor with default values for all the fields.

So is using wrapper structs for each field the correct way? Seems IMHO like a long overkill…

```julia
struct Xwrap
    value::Int
end

struct Ywrap
    value::Int
end

struct Zwrap
    value::Int
end

struct xyz
    x::Int
    y::Int
    z::Int
    xyz(x::Xwrap,y::Ywrap)=new(x.value,y.value,0)
    xyz(y::Ywrap,z::Zwrap)=new(0,y.value,z.value)
end

xyz1 = xyz(Xwrap(1), Ywrap(2))
xyz2 = xyz(Ywrap(3), Zwrap(4))

```

Any suggestions on how to make it clear and concise are welcome, thanks!

---

<div class="post-metadata">

**Author:** ![goerch](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/goerch/32/29122_2.png) [@goerch](https://discourse.julialang.org/u/goerch)\
**Post date:** [April 18, 2022, 6:37am UTC](https://discourse.julialang.org/t/struct-with-partial-explicit-constructs-that-init-subset-of-fields/79618/2 "2022-04-18T06:37:46Z")

</div>

The first idea that crossed my mind, not sure if it is any good:

```julia
struct abc
    a::Int
    b::Int
    c::Int
    abc(a, b, ::Val{:ab}) = new(a, b, 0)
    abc(b, c, ::Val{:bc}) = new(0, b, c)
end

@show abc1 = abc(1, 2, Val(:ab))
@show abc2 = abc(3, 4, Val(:bc))

```

yielding

```julia
abc1 = abc(1, 2, Val(:ab)) = abc(1, 2, 0)
abc2 = abc(3, 4, Val(:bc)) = abc(0, 3, 4)

```

---

<div class="post-metadata">

**Author:** ![jondea](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jondea/32/39086_2.png) [@jondea](https://discourse.julialang.org/u/jondea)\
**Post date:** [April 18, 2022, 7:05am UTC](https://discourse.julialang.org/t/struct-with-partial-explicit-constructs-that-init-subset-of-fields/79618/3 "2022-04-18T07:05:34Z")

</div>

What if the constructors were the same as you have them, but with keyword arguments instead of default positional arguments? (Add semicolons after the opening parentheses to the inner constructors.) If I remember correctly you can also make them mandatory by not providing any value, in fact you might have to do this to make the dispatch unambiguous. I don’t have a terminal to hand so I can’t check sorry.

Edit: I don’t this will work as described because [apparently you can’t dispatch on keyword arguments,](https://stackoverflow.com/questions/59674079/julia-multiple-dispatch-based-on-named-arguments) even if they are mandatory. I think I have a sneaky way around it though, I’ll post it if I get it working…

---

<div class="post-metadata">

**Author:** ![Vasily\_Pisarev](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vasily_pisarev/32/7929_2.png) [@Vasily\_Pisarev](https://discourse.julialang.org/u/Vasily_Pisarev)\
**Post date:** [April 18, 2022, 7:07am UTC](https://discourse.julialang.org/t/struct-with-partial-explicit-constructs-that-init-subset-of-fields/79618/4 "2022-04-18T07:07:36Z")

</div>

If you have sane defaults for the uninitialized fields, then `@Base.kwdef` seems appropriate:

```julia-auto
  @kwdef typedef

```

This is a helper macro that automatically defines a keyword-based constructor for the type declared in the expression `typedef`, which must be a `struct` or `mutable struct` expression. The default argument is supplied by declaring fields of the form `field::T = default` or `field = default`. If no default is provided then the keyword argument becomes a required keyword argument in the resulting type constructor.

Inner constructors can still be defined, but at least one should accept arguments in the same form as the default inner constructor (i.e. one positional argument per field) in order to function correctly with the keyword outer constructor.

# Examples

```julia-auto
  julia> Base.@kwdef struct Foo
             a::Int = 1 # specified default
             b::String # required keyword
         end
  Foo
  
  julia> Foo(b="hi")
  Foo(1, "hi")
  
  julia> Foo()
  ERROR: UndefKeywordError: keyword argument b not assigned
  Stacktrace:
  [...]

```

---

<div class="post-metadata">

**Author:** ![goerch](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/goerch/32/29122_2.png) [@goerch](https://discourse.julialang.org/u/goerch)\
**Post date:** [April 18, 2022, 7:12am UTC](https://discourse.julialang.org/t/struct-with-partial-explicit-constructs-that-init-subset-of-fields/79618/5 "2022-04-18T07:12:33Z")

</div>

> [@Vasily\_Pisarev](#):
>
> If you have sane defaults for the uninitialized fields, then `@Base.kwdef` seems appropriate

This looks reasonable, but OP wants

> [@FireCrumb](#):
>
> Note that _not every combination_ of fields is acceptable, so I can’t just have a single constructor with default values for all the fields.

Not sure if this is possible with `@Base.kwdef`?

---

<div class="post-metadata">

**Author:** ![Vasily\_Pisarev](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vasily_pisarev/32/7929_2.png) [@Vasily\_Pisarev](https://discourse.julialang.org/u/Vasily_Pisarev)\
**Post date:** [April 18, 2022, 8:41am UTC](https://discourse.julialang.org/t/struct-with-partial-explicit-constructs-that-init-subset-of-fields/79618/6 "2022-04-18T08:41:41Z")

</div>

Right, that’s not possible with `@kwdef`.

Then, manual dispatch with keywords is probably the best one can get, albeit a bit tedious if there are lots of combinations:

```julia
struct abc
    a::Int
    b::Int
    c::Int
end

abc(; a=nothing, b=nothing, c=nothing) = __abc(a, b, c)

__abc(a::Number, b::Number, c::Nothing) = abc(Int(a), Int(b), 0)
__abc(a::Nothing, b::Number, c::Number) = abc(0, Int(b), Int(c))

```

---

<div class="post-metadata">

**Author:** ![FireCrumb](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/firecrumb/32/35370_2.png) [@FireCrumb](https://discourse.julialang.org/u/FireCrumb)\
**Post date:** [April 18, 2022, 9:13am UTC](https://discourse.julialang.org/t/struct-with-partial-explicit-constructs-that-init-subset-of-fields/79618/7 "2022-04-18T09:13:10Z")

</div>

In the actual case, the fields are of different types, and there are many more of them.  
So I prefer a syntax where there are more explicit key-value pairs of field name and value.

---

<div class="post-metadata">

**Author:** ![FireCrumb](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/firecrumb/32/35370_2.png) [@FireCrumb](https://discourse.julialang.org/u/FireCrumb)\
**Post date:** [April 18, 2022, 9:28am UTC](https://discourse.julialang.org/t/struct-with-partial-explicit-constructs-that-init-subset-of-fields/79618/8 "2022-04-18T09:28:58Z")

</div>

Re `a::Nothing`, that’s very interesting, thanks!  
What does it mean? That a parameter can be skipped and it will be ignored?

Why doesn’t it work when I use a function?

```julia
f1(a::Nothing,b::Number) = println("f(b)")
f1(a::Number,b::Nothing) = println("f(a)")
f1(a::Number,b::Number) = println("f(a,b)")

f1(a=1)

```

I’m getting this error:

```julia
MethodError: no method matching f1(; a=1)
Closest candidates are:
  f1(::Nothing, ::Int64) at In[62]:1 got unsupported keyword argument "a"
  f1(::Nothing, ::Number) at In[65]:1 got unsupported keyword argument "a"
  f1(::Nothing, ::Any) at In[61]:1 got unsupported keyword argument "a"

```

And this code:

```julia
f1(; a::Nothing,b::Number) = println("f(b)")
f1(; a::Number,b::Nothing) = println("f(a)")
f1(; a::Number,b::Number) = println("f(a,b)")

f1(a=1)

```

Gives this error:

```julia
UndefKeywordError: keyword argument b not assigned

```

What am I missing about keyword arguments here?

---

<div class="post-metadata">

**Author:** ![jondea](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jondea/32/39086_2.png) [@jondea](https://discourse.julialang.org/u/jondea)\
**Post date:** [April 18, 2022, 11:15am UTC](https://discourse.julialang.org/t/struct-with-partial-explicit-constructs-that-init-subset-of-fields/79618/9 "2022-04-18T11:15:56Z")

</div>

I think you are confusing positional and keyword arguments in your first example. You are defining your function with positional arguments then trying to call it with keyword arguments (by specifying a=1 in the function call, it makes it a keyword argument).

In the second example, you’ve specified the _type_ of a,b and c but not the default _value_. That means that they are _all_ mandatory when calling that particular function signature.

You might find it helpful to have a good read of the [functions documentation](https://docs.julialang.org/en/v1/manual/functions/).

---

<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 18, 2022, 12:56pm UTC](https://discourse.julialang.org/t/struct-with-partial-explicit-constructs-that-init-subset-of-fields/79618/10 "2022-04-18T12:56:01Z")

</div>

IMO a variation of your initial proposal is what may suite the best. Perhaps if these acceptable combinations of parameters comprise different setups, you can use something like:

```julia
struct Setup1
   a::Int
   b::Int
end
struct Setup2
   a::Int
   c::Int
end
@kwdef struct xyz
    a::Int = 0
    b::Int = 0
    c::Int = 0
end
xyz(s::Setup1) = xyz(;a=s.a, b=s.b)
xyz(s::Setup2) = xyz(;a=s.a, c=s.c)

mysetup = xyz(Setup1(a=1,b=2))
etc.

```

---

<div class="post-metadata">

**Author:** ![Henrique\_Becker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henrique_becker/32/15443_2.png) [@Henrique\_Becker](https://discourse.julialang.org/u/Henrique_Becker)\
**Post date:** [April 18, 2022, 1:46pm UTC](https://discourse.julialang.org/t/struct-with-partial-explicit-constructs-that-init-subset-of-fields/79618/11 "2022-04-18T13:46:54Z")

</div>

> [@FireCrumb](#):
>
> Re `a::Nothing` , that’s very interesting, thanks!  
> What does it mean? That a parameter can be skipped and it will be ignored?

`Nothing` is just a type with a single value: `nothing` (all lowercase). It does not have any special behaviour that allows for skipping or ignoring parameters, but you can use it for this purpose (as you could use any other type, especially the empty ones). You can use them in both positional and keyword arguments but each use is considerably different.

In positional arguments:

```julia
julia> f1(a::Nothing,b::Number) = println("f(b)")
f1 (generic function with 1 method)

julia> f1(a::Number,b::Nothing) = println("f(a)")
f1 (generic function with 2 methods)

julia> f1(a::Number,b::Number) = println("f(a,b)")
f1 (generic function with 3 methods)

julia> f1(nothing, 10)
f(b)

julia> f1(10, nothing)
f(a)

julia> f1(10, 10)
f(a,b)

```

Basically, you can use it to mark which parameters you are not passing. My only annoyance with this solutions is that `nothing` is too long of a word. You can use a gloabl `const SKIP = nothing` or something like that to reduce the typing. Or even create a new empty type like `struct S; end` but then you need to define and call the code the following way:

```julia
julia> f1(a::S,b::Number) = println("f(b)")
f1 (generic function with 1 method)

julia> f1(a::Number,b::S) = println("f(a)")
f1 (generic function with 2 methods)

julia> f1(a::Number,b::Number) = println("f(a,b)")
f1 (generic function with 3 methods)

julia> f1(S(), 10)
f(b)

julia> f1(10, S())
f(a)

julia> f1(10, 10)
f(a,b)

```

The use of nothing in keyword parameters is considerably different because you do the dispatch manually inside the function.

```julia
julia> function f1(; a = nothing, b = nothing)
           if a !== nothing && b === nothing
               println("f(a)")
           elseif a === nothing && b !== nothing
               println("f(b)")
           elseif a !== nothing && b !== nothing
               println("f(a, b)")
           end
       end
f1 (generic function with 1 method)

julia> f1(; a = 1)
f(a)

julia> f1(b = 2)
f(b)

julia> f1(; b = 1, a = 2)
f(a, b)

```

You can also combine the two approaches (positional and keyword), you cannot combine them at the same call, but you can call either way and gain the benefit you do not need the manual dispatch (the positional solution will do the dispatch for you). Note that if you pass a combination of parameters that do not exist to the keyword alternative it will accept it and pass it to the positional that will then error with `MethodError` (I think this is good behaviour).

```julia
julia> f1(a::Nothing,b::Number) = println("f(b)")
f1 (generic function with 1 method)

julia> f1(a::Number,b::Nothing) = println("f(a)")
f1 (generic function with 2 methods)

julia> f1(a::Number,b::Number) = println("f(a,b)")
f1 (generic function with 3 methods)

julia> f1(; a = nothing, b = nothing) = f1(a, b)
f1 (generic function with 4 methods)

julia> f1(nothing, 1)
f(b)

julia> f1(1, nothing)
f(a)

julia> f1(1, 1)
f(a,b)

julia> f1(; a = 1)
f(a)

julia> f1(b = 1)
f(b)

julia> f1(; b = 2, a = 1)
f(a,b)

julia> f1()
ERROR: MethodError: no method matching f1(::Nothing, ::Nothing)
Closest candidates are:
  f1(::Nothing, ::Number) at REPL[1]:1
  f1(::Number, ::Nothing) at REPL[2]:1
Stacktrace:
 [1] f1(; a::Nothing, b::Nothing) at ./REPL[4]:1
 [2] f1() at ./REPL[4]:1
 [3] top-level scope at REPL[13]:1

```

---

<div class="post-metadata">

**Author:** ![FireCrumb](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/firecrumb/32/35370_2.png) [@FireCrumb](https://discourse.julialang.org/u/FireCrumb)\
**Post date:** [April 18, 2022, 6:07pm UTC](https://discourse.julialang.org/t/struct-with-partial-explicit-constructs-that-init-subset-of-fields/79618/12 "2022-04-18T18:07:59Z")

</div>

Thanks for `Nothing` and `nothing`, it was much more than nothing! 😆

What if I don’t have the parameter names, but just their type, do I have to wrap them for multiple dispatch to distinguish between them?

Say I have this use case with two fields of the same value type but different meaning:

```julia
const VelocityT = Float32
const AccelerationT = Float32

struct MovementInfo
    veloc::VelocityT
    accel::AccelerationT
end

struct WrapVelocityT value::VelocityT end
struct WrapAccelerationT value::AccelerationT end

MovementInfo(v::VelocityT) = MovementInfo(v,0.0)
MovementInfo(a::AccelerationT) = MovementInfo(0.0,a)
MovementInfo(v::WrapVelocityT) = MovementInfo(v.value,0.0)
MovementInfo(a::WrapAccelerationT) = MovementInfo(0.0,a.value)

```

Then `m1` and `m2` are the same (_not_ what we wanted), and only `m3` and `m4` are different and correct field is assigned.

```julia
m1 = MovementInfo(VelocityT(5.0)) # MovementInfo(0.0f0, 5.0f0) -- incorrect
m2 = MovementInfo(AccelerationT(5.0)) # MovementInfo(0.0f0, 5.0f0)

m3 = MovementInfo(WrapVelocityT(5.0)) # MovementInfo(5.0f0, 0.0f0)
m4 = MovementInfo(WrapAccelerationT(5.0)) # MovementInfo(0.0f0, 5.0f0)

```

Is this proper use of types and wrappers?

Which way do you think is better (keyword argument or wrapper arguments) and why?

---

<div class="post-metadata">

**Author:** ![Henrique\_Becker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henrique_becker/32/15443_2.png) [@Henrique\_Becker](https://discourse.julialang.org/u/Henrique_Becker)\
**Post date:** [April 18, 2022, 7:21pm UTC](https://discourse.julialang.org/t/struct-with-partial-explicit-constructs-that-init-subset-of-fields/79618/13 "2022-04-18T19:21:54Z")

</div>

> [@FireCrumb](#):
>
> What if I don’t have the parameter names, but just their type, do I have to wrap them for multiple dispatch to distinguish between them?

Not entirely sure if I understand. How do you would **not** have parameter names? Both positional and keyword parameters generally have names.

> [@FireCrumb](#):
>
> Then `m1` and `m2` are the same ( _not_ what we wanted), and only `m3` and `m4` are different and correct field is assigned.

`m1` and `m2` are the same because `VelocityT` and `AccelerationT` are not new types, just aliases for `Float32`, so the second definition has the same signature and replaces the first. The whole code could be rewritten replacing both of them by `Float32` and it would be semantically exactly the same.

> [@FireCrumb](#):
>
> Is this proper use of types and wrappers?

`WrapVelocityT` and `WrapAccelerationT` are pretty standard wrappers. I see nothing wrong about them.

> [@FireCrumb](#):
>
> Which way do you think is better (keyword argument or wrapper arguments) and why?

It will always depends on your case. I think wrappers add some extra complexity and inconveniences, so if you go with them their use must be justified. If two or more wrapped values can be passed they may end up harder to combine with each other too: either they need to be given in the right order, or you need to manually allow them to be given in any order. I would go with my keyword + positional solution (the last example of my last post) because it allows the flexibility of calling with any combination of parameters in any order, and if you did not create a positional method that takes such combination then the user will receive a nice `MethodError` that will more or less point them to the right direction. You can also detect the error yourself and throw a better error message without needing to change anything externally (just the inner code of the keyword method). That said, I think that [Gadfly.jl](http://gadflyjl.org/stable/) uses wrappers extensively to implement their grammar of graphics.

---

<div class="post-metadata">

**Author:** ![FireCrumb](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/firecrumb/32/35370_2.png) [@FireCrumb](https://discourse.julialang.org/u/FireCrumb)\
**Post date:** [May 13, 2022, 9:29am UTC](https://discourse.julialang.org/t/struct-with-partial-explicit-constructs-that-init-subset-of-fields/79618/14 "2022-05-13T09:29:27Z")

</div>

> [@Henrique\_Becker](#):
>
> That said, I think that [Gadfly.jl](http://gadflyjl.org/stable/) uses wrappers extensively to implement their grammar of graphics.

For more explicit reference, here is how it does it with a macro that defines a type [1] and here is how this macro is used to create a type [2].

Taking that example, I was able to build my `@boxedtype` macro:

```julia
import Base: copy, convert

macro boxedtype(name::Symbol, type::Symbol)
    esc(quote
        Core.@ __doc__ struct $(name)
            value::$(type)
        end
        Base.copy(a::$(name)) = $(name)(a)
        Base.convert(::Type{$(type)}, x::$(name)) = x.value
        $(name)
    end)
end

"Foo1 boxes Int"
@boxedtype Foo1 Int

"Foo2 boxes Float"
@boxedtype Foo2 Float32

process(x::Foo1) = "foo1"
process(x::Foo2) = "foo2"
process(x::Int) = "int"
process(x::Float32) = "float"

y1 = Foo1(15)
y2 = Foo2(3.14)

@assert process(y1) == "foo1"
@assert process(y2) == "foo2"
@assert process(y1.value) == "int"
@assert process(y2.value) == "float"

function explicit_conv_type(x::Foo1)
    z::Int = x
    return z * 2
end

@assert explicit_conv_type(y1) == Int(30)

```

[1] [https://github.com/GiovineItalia/Gadfly.jl/blob/master/src/varset.jl](https://github.com/GiovineItalia/Gadfly.jl/blob/master/src/varset.jl)  
[2] [https://github.com/GiovineItalia/Gadfly.jl/blob/master/src/data.jl](https://github.com/GiovineItalia/Gadfly.jl/blob/master/src/data.jl)
