How to create an instance of a mutable composite type with most fields left empty?

Let’s say I have a mutable composite type and want to create an instance of it. However, at first, I only want to initialise one of the fields (lets say in the example bellow Cost = 120.5) and leave all the others empty. In my real use case of portfolio optimisation the composite type has 38 fields, most of them likely to be left empty, so this would be convenient.

abstract type Furniture end
mutable struct Sofa <: Furniture
    Name::String
    Colour:: Symbol
    Size::Vector{Float64}
    Cost::Float64
end

Of course by “brute force” one can always do, for instance

s = Sofa("",Symbol(""),[],NaN)
s.Cost = 120.5 

but I was hoping to be able to do something similar to this instead

s = Sofa()      # errors naturally
s.Cost = 120.5 

Thanks in advance!

Have a look at Constructors · The Julia Language

You could do this:

julia> using Parameters

julia> abstract type Furniture end

julia> @with_kw mutable struct Sofa <: Furniture
           Name::Union{String,Nothing} = nothing
           Colour::Union{Symbol,Nothing} = nothing
           Size::Union{Vector{Float64},Nothing} = nothing
           Cost::Union{Float64,Nothing} = nothing
       end
Sofa

julia> s = Sofa()
Sofa
  Name: Nothing nothing
  Colour: Nothing nothing
  Size: Nothing nothing
  Cost: Nothing nothing


julia> s.Cost = 120.5
120.5

julia> s
Sofa
  Name: Nothing nothing
  Colour: Nothing nothing
  Size: Nothing nothing
  Cost: Float64 120.5

It doesn’t look very nice, though. One alternative is to initialize the fields with default values of the expected types instead of nothing and then you would not need to use the Union types.

Edit: apparently missing has advantages relative to nothing.

1 Like

See LazilyInitializedFields.jl

You still have to initialize all fields with uninit, but the package makes working with partially initialized structs a bit safer.

2 Likes

Assuming you could do s = Sofa(), what should immediately calling s.Cost do? If the answer is error, then you can do this:

julia> mutable struct Foo
           x
           y
           function Foo(x)
               f = new()
               f.x = x
               f
           end
       end

julia> Foo(1)
Foo(1, #undef)

julia> Foo(1).x
1

julia> Foo(1).y
ERROR: UndefRefError: access to undefined reference
Stacktrace:
 [1] getproperty(::Foo, ::Symbol) at ./Base.jl:33
 [2] top-level scope at REPL[2143]:1
2 Likes