# Incomplete initialization (control which fields are initialized in \`new\`)

**URL:** <https://discourse.julialang.org/t/incomplete-initialization-control-which-fields-are-initialized-in-new/43452>\
**Category:** General Usage\
**Tags:** struct\
**Created:** [July 21, 2020, 10:06pm UTC](https://discourse.julialang.org/t/incomplete-initialization-control-which-fields-are-initialized-in-new/43452 "2020-07-21T22:06:01Z")\
**Posts on this page:** 14\
**Page:** 2

<div class="post-metadata">

**Author:** ![FedericoStra](https://avatars.discourse-cdn.com/v4/letter/f/76d3ee/32.png) [@FedericoStra](https://discourse.julialang.org/u/FedericoStra)\
**Post date:** [July 22, 2020, 9:40pm UTC](https://discourse.julialang.org/t/incomplete-initialization-control-which-fields-are-initialized-in-new/43452/21 "2020-07-22T21:40:08Z")

</div>

> [@marius311](#):
>
> Makes sense, but in case you weren’t aware, note that Julia has some special optimizations for these small union `Union{T,Nothing}` kind of things, so the smallness of the overhead might surprise you, might be worth doing a quick benchmark.

Unfortunately I believe that the optimizations are only possible when `T` is of reference type and not plain data, because in the former case one could use the `NULL` pointer to represent the `nothing`. If `T` is plain data then I believe that `Union{T,Nothing}` requires a hidden flag behind the scene to identify which variant is currently in use. This penalizes the plain data case (`Int`, `Float64`, …), which is admittedly the most interesting. I might be completely wrong about this; this is just my current understanding. (A bit like rust can optimize `Option<&'a T>` because references are never null.)

I will try to run some benchmarks as soon as I have implemented all 43 versions of the same code 😂

* * *

> [@marius311](#):
>
> Alternatively, you could always do
> 
> ```julia
> Base.@kwdef struct P{T,X<:Union{T,Nothing},Y<:Union{T,Nothing}}
> x::X = nothing
> y::Y = nothing
> end
> 
> ```
> 
> which removes any instability

It removes it here, but it introduces it as soon as you want heterogeneous collections

```julia
Vector{P{T,X,Y} where {X<:Union{T,Nothing}, Y<:Union{T,Nothing}}}

```

which is something that I want. This approach wouldn’t work for me I think.

* * *

> [@Vasily\_Pisarev](#):
>
> In practice, that may be an even easier case than the original.  
> If `s` and `t` are never needed together, then `Union{S,T}` is the proper choice.

That forces you to collate two _a priori_ independent variables (think of a name and an age) for no good reason. Imagine a situation where you always know either the name or the age:

```julia
struct S
    name_or_age::Union{String, Int}
    ...
end 

```

This doesn’t look very good.

In the most general situation, again, it might not be straightforward to take into account all possible combinations of “definedness” of the fields, and arbitrarily grouping them under the same name seems a path to insanity.

If I weren’t super concerned with performance I would definitely go with the `Union{T,Nothing}` approach, which at least expresses the semantic adequately. I’ll come back with some benchmarks if I manage to get some meaningful ones.

* * *

> [@Vasily\_Pisarev](#):
>
> But having a clean way to skip initialization of some fields if needed is, for sure, better than use of workarounds and cryptic idioms.

👍 🚀 💯

---

<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:** [July 22, 2020, 11:46pm UTC](https://discourse.julialang.org/t/incomplete-initialization-control-which-fields-are-initialized-in-new/43452/22 "2020-07-22T23:46:56Z")

</div>

> [@FedericoStra](#):
>
> That forces you to collate two _a priori_ independent variables (think of a name and an age) for no good reason. Imagine a situation where you always know either the name or the age:

Ok, but the `struct Either` that triggered this suggestion is literally a immutable type with a `Bool` to specify which field _is defined_ (or, at least, is the one that can be looked at). For that case, the suggestion seem appropriate, no?

---

<div class="post-metadata">

**Author:** ![abulak](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abulak/32/28314_2.png) [@abulak](https://discourse.julialang.org/u/abulak)\
**Post date:** [July 23, 2020, 9:57am UTC](https://discourse.julialang.org/t/incomplete-initialization-control-which-fields-are-initialized-in-new/43452/23 "2020-07-23T09:57:29Z")

</div>

@FredericoStra Another possibility for you is to define an assessor function and treat the order of fields in your struct as an implementation detail. E.g.

```julia
struct Interval{T}
    _left_kind::Symbol
    _right_kind::Symbol
    _one_end::T
    _other_end::T
    Interval{T}(ls::Symbol, rs::Symbol, val) where T = new{T}(ls, rs, val)
    Interval{T}(ls::Symbol, rs::Symbol, vall, valr) where T = new{T}(ls, rs, vall, valr)
end
function left_end(int::Interval)
    int._left_kind == :inf && throw("interval is left unbounded")
    return int._one_end
end
function right_end(int::Interval)
    int._right_kind == :inf && throw("interval is right unbounded")
    int._left_kind == :inf && return int._one_end
    return int._other_end
end

```

therefore in memory you represent

- `(-∞, a])` as `(:inf, :closed, a)`,
- `(a, ∞)` as `(:open, :inf, a)` and
- `[a, b)` as `(:closed, :open, a, b)`

As sugar on top let’s define

```julia
function Base.getproperty(int::Interval, s::Symbol)
    s == :left && return left_end(int)
    s == :right && return right_end(int)
    return getfield(int, s)
end

```

so that you can use `int.left` and `int.right` in your code 🙂 would that work for you?

If you really care about performance I guess it’s better to encode possible combinations bit-wise in an `UInt` (even `UInt8` is plenty of space for this purpose), instead of storing symbols in the struct.

---

<div class="post-metadata">

**Author:** ![FedericoStra](https://avatars.discourse-cdn.com/v4/letter/f/76d3ee/32.png) [@FedericoStra](https://discourse.julialang.org/u/FedericoStra)\
**Post date:** [July 23, 2020, 4:33pm UTC](https://discourse.julialang.org/t/incomplete-initialization-control-which-fields-are-initialized-in-new/43452/24 "2020-07-23T16:33:19Z")

</div>

> [@Henrique\_Becker](#):
>
> Ok, but the `struct Either` that triggered this suggestion is literally a immutable type with a `Bool` to specify which field _is defined_ (or, at least, is the one that can be looked at). For that case, the suggestion seem appropriate, no?

Yes, but that was just an oversimplified example to illustrate a point.

I’m interested in the general situation where there are more complex invariants that determine which fields are to access or not.

In C you would not introduce unions or stuff like that; you would simply skip the initialization of the unneeded fields (and check very very very very carefully that you don’t accidentally access them, otherwise… Demons!).

* * *

> [@abulak](#):
>
> Another possibility for you is to define an assessor function and treat the order of fields in your struct as an implementation detail. E.g.

This is pretty much what I wrote at the end of [this comment](https://discourse.julialang.org/t/incomplete-initialization-control-which-fields-are-initialized-in-new/43452/9). I have to praise the clarity of your implementation, though, especially regarding the use of `getproperty`. The idea of storing data in the incorrect field just to work around a limitation of `new` doesn’t look very satisfying. Now you have made unnecessarily complicated the access to `.right`. In larger situations this is extremely error prone, if not totally confusing at all. Moreover, you need to performs the additional checks every time to try to access the field.

* * *

> [@abulak](#):
>
> If you really care about performance I guess it’s better to encode possible combinations bit-wise in an `UInt` (even `UInt8` is plenty of space for this purpose), instead of storing symbols in the struct.

I agree. The usage of an explicit `Symbol` flag was just to exemplify something that keeps track of the internal state of the `struct`. In general it might not even be a single flag, but a combination of few of them.

* * *

I feel this thread has become very interesting to read. A lot of good ideas, thank you all! 🙂

I still want keyword arguments for `new`, though! 😃

---

<div class="post-metadata">

**Author:** ![abulak](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abulak/32/28314_2.png) [@abulak](https://discourse.julialang.org/u/abulak)\
**Post date:** [July 23, 2020, 9:13pm UTC](https://discourse.julialang.org/t/incomplete-initialization-control-which-fields-are-initialized-in-new/43452/25 "2020-07-23T21:13:28Z")

</div>

> [@FedericoStra](#):
>
> This is pretty much what I wrote at the end of [this comment](https://discourse.julialang.org/t/incomplete-initialization-control-which-fields-are-initialized-in-new/43452/9). I have to praise the clarity of your implementation, though, especially regarding the use of `getproperty` . The idea of storing data in the incorrect field just to work around a limitation of `new` doesn’t look very satisfying. Now you have made unnecessarily complicated the access to `.right` . In larger situations this is extremely error prone, if not totally confusing at all. Moreover, you need to performs the additional checks every time to try to access the field.

All you need are **properties** : `left` and `right` for an interval, so the concept of “incorrect field” is ill defined. Where and how the data is stored is an implementation detail. Would names `_don't_access_me_field` and `_don't_access_me_other_filed` better convey the message? 😉

As far as I’m concerned it’s clean and rather safe: one pays the price of one additional `if` in the accesor for one (possibly unnecessary) allocation. I’d accept such code in my repository 😃

But the ugliness/complication is in the eye of the beholder, if you come to a solution more to your liking, please don’t forget to share it here!

---

<div class="post-metadata">

**Author:** ![heliosdrm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/heliosdrm/32/3851_2.png) [@heliosdrm](https://discourse.julialang.org/u/heliosdrm)\
**Post date:** [July 24, 2020, 7:42am UTC](https://discourse.julialang.org/t/incomplete-initialization-control-which-fields-are-initialized-in-new/43452/26 "2020-07-24T07:42:23Z")

</div>

> [@Vasily\_Pisarev](#):
>
> As long as one of the fields is not going to be accessed, why not initialize both with the same value?

I think that this solution is even better than using incomplete instances of the `Interval` object, because if both `left` and `right` fields refer to exactly the same object, you can be absolutely sure that the undefined (and unnecessary) bound won’t allocate any memory.

An alternative to achieve this is making `Interval` an abstract type, and define special subtypes depending on their bounded ends.

```julia
abstract type Interval{T} end

struct RightBoundInterval{T} <: Interval{T}
    right_kind::Symbol
    right::T
end

struct LeftBoundInterval{T} <: Interval{T}
    left_kind::Symbol
    left::T
end

struct BoundedInterval{T} <: Interval{T}
    left_kind::Symbol
    right_kind::Symbol
    left::T
    right::T
end

Interval(leftkind, rightkind, left, right) = BoundedInterval(leftkind, rightkind, left, right)

```

Then you can make other constructors for `Interval`s unbounded on either side. An advantage is that you may know whether an interval is right- or left-unbounded by just checking its type, without looking into its fields. But if you still want to do it that way, you can also overload `getproperty`:

```julia
function Base.getproperty(i::RightBoundInterval, field::Symbol)
    (field == :left_kind) ? :unbounded : getfield(i, field)
end

function Base.getproperty(i::LeftBoundInterval, field::Symbol)
    (field == :right_kind) ? :unbounded : getfield(i, field)
end

```

Thus:

```julia
julia> x = LeftBoundInterval(:open, 0.0)
LeftBoundInterval{Float64}(:open, 0.0)

julia> x.left_kind
:open

julia> x.left
0.0

julia> x.right_kind
:unbounded

julia> x.right
ERROR: type LeftBoundInterval has no field right

```

---

<div class="post-metadata">

**Author:** ![heliosdrm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/heliosdrm/32/3851_2.png) [@heliosdrm](https://discourse.julialang.org/u/heliosdrm)\
**Post date:** [July 24, 2020, 8:00am UTC](https://discourse.julialang.org/t/incomplete-initialization-control-which-fields-are-initialized-in-new/43452/27 "2020-07-24T08:00:00Z")

</div>

Yet another advantage of using subtypes for left- or right-bounded intervals: that way it’s pretty straightforward to give such “unbounded values” for specific types (if wanted):

```julia
function Base.getproperty(x::LeftBoundInterval{F}, field::Symbol) where {F <:AbstractFloat}
    if field == :right_kind
        return :unbounded
    elseif field == :right
        return F(Inf)
    else
        return getfield(x, field)
    end
end

```

```julia
julia> x = LeftBoundInterval(:open, 0.0)
LeftBoundInterval{Float64}(:open, 0.0)

julia> x.right
Inf

```

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [July 24, 2020, 9:19am UTC](https://discourse.julialang.org/t/incomplete-initialization-control-which-fields-are-initialized-in-new/43452/28 "2020-07-24T09:19:59Z")

</div>

> [@heliosdrm](#):
>
> making `Interval` an abstract type, and define special subtypes depending on their bounded ends

I proposed that [above](https://discourse.julialang.org/t/incomplete-initialization-control-which-fields-are-initialized-in-new/43452/8), but @FedericoStra prefers that everything is the same type.

---

<div class="post-metadata">

**Author:** ![heliosdrm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/heliosdrm/32/3851_2.png) [@heliosdrm](https://discourse.julialang.org/u/heliosdrm)\
**Post date:** [July 24, 2020, 10:13am UTC](https://discourse.julialang.org/t/incomplete-initialization-control-which-fields-are-initialized-in-new/43452/29 "2020-07-24T10:13:33Z")

</div>

Oh, you’re right. Sorry for overlooking!

Then, the idea of storing the same value in both ends looks a good workaround for me. Maybe even both ideas could be combined, to ensure that you can make homogeneous arrays with “fake” bounded intervals:

```julia
function Base.convert(::Type{BoundedInterval{T}}, x::LeftBoundInterval) where {T}
    BoundedInterval{T}(x.left_kind, :unbounded, x.left, x.left)
end

function Base.convert(::Type{BoundedInterval{T}}, x::RightBoundInterval) where {T}
    BoundedInterval{T}(:unbounded, x.right_kind, x.right, x.right)
end

function Base.convert(::Type{BoundedInterval{T}}, x::BoundedInterval{S}) where {T, S}
    BoundedInterval{T}(:left_kind, x.right_kind, x.left, x.right)
end

function Base.convert(::Type{BoundedInterval}, x::S) where {S<:Interval{T} where T}
    convert(BoundedInterval{T}, x)
end

```

```julia
julia> bounded = Interval(:open, :closed, 0.0, 1.0)
BoundedInterval{Float64}(:open, :closed, 0.0, 1.0)

julia> unbounded = LeftBoundInterval(:open, 0)
LeftBoundInterval{Int64}(:open, 0)

julia> [bounded, unbounded] # heterogeneous
2-element Array{Interval,1}:
 BoundedInterval{Float64}(:open, :closed, 0.0, 1.0)
 LeftBoundInterval{Int64}(:open, 0)

julia> intervals = Array{BoundedInterval}(undef, 2)
2-element Array{BoundedInterval,1}:
 #undef
 #undef

julia> intervals[1] = bounded; intervals[2] = unbounded;

julia> intervals # still heterogeneous (different parameter type)
2-element Array{BoundedInterval,1}:
 BoundedInterval{Float64}(:left_kind, :closed, 0.0, 1.0)
 BoundedInterval{Int64}(:open, :unbounded, 0, 0)

julia> intervals = Array{BoundedInterval{Float64}}(undef, 2)
2-element Array{BoundedInterval{Float64},1}:
 #undef
 #undef

julia> intervals[1] = bounded; intervals[2] = unbounded;

julia> intervals # homogeneous!
2-element Array{BoundedInterval{Float64},1}:
 BoundedInterval{Float64}(:left_kind, :closed, 0.0, 1.0)
 BoundedInterval{Float64}(:open, :unbounded, 0.0, 0.0)

```

---

<div class="post-metadata">

**Author:** ![FedericoStra](https://avatars.discourse-cdn.com/v4/letter/f/76d3ee/32.png) [@FedericoStra](https://discourse.julialang.org/u/FedericoStra)\
**Post date:** [July 24, 2020, 10:24am UTC](https://discourse.julialang.org/t/incomplete-initialization-control-which-fields-are-initialized-in-new/43452/30 "2020-07-24T10:24:25Z")

</div>

> [@heliosdrm](#):
>
> > [@Vasily\_Pisarev](#):
> >
> > As long as one of the fields is not going to be accessed, why not initialize both with the same value?
> 
> I think that this solution is even better than using incomplete instances of the `Interval` object, because if both `left` and `right` fields refer to exactly the same object, you can be absolutely sure that the undefined (and unnecessary) bound won’t allocate any memory.

That doesn’t make much sense. If you skip the initialization of a field then for sure you are not allocating memory unnecessarily, and in addition you skip also the unneeded assignment. So skipping the initialization has to be always more efficient than assigning an arbitrary value to a field, which you cannot even to in general

```julia
struct P{S,T}
    s::S
    t::T
end

```

because you don’t have another value to reuse. This idea of duplicating a field is a hack that might work in specific cases, but is definitely not a versatile solution that applies to all circumstances.

* * *

> [@heliosdrm](#):
>
> An alternative to achieve this is making `Interval` an abstract type, and define special subtypes depending on their bounded ends.

That’s completely unrelated to the question. This introduces dynamic dispatch when you want to work with `Vector{Interval{T}}`, which comes with a performance penalty.

> [@heliosdrm](#):
>
> An advantage is that you may know whether an interval is right- or left-unbounded by just checking its type, without looking into its fields.

As I said, this is also a disadvantage when you work with collections of intervals of heterogeneous types, because it’s more expensive than checking some fields.

This architecture of course is suitable for some cases, but doesn’t solve the incomplete initialization issue at all. My need of incompletely initialization is precisely to avoid this dynamic approach.

* * *

> [@heliosdrm](#):
>
> Yet another advantage of using subtypes for left- or right-bounded intervals: that way it’s pretty straightforward to give such “unbounded values” for specific types (if wanted):
> 
> ```julia
> function Base.getproperty(x::LeftBoundInterval{F}, field::Symbol) where {F <:AbstractFloat}
> if field == :right_kind
> return :unbounded
> elseif field == :right
> return F(Inf)
> else
> return getfield(x, field)
> end
> end
> 
> ```

That’s very nice, but again very dynamic in nature when you work with heterogeneous collections.

---

<div class="post-metadata">

**Author:** ![heliosdrm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/heliosdrm/32/3851_2.png) [@heliosdrm](https://discourse.julialang.org/u/heliosdrm)\
**Post date:** [July 24, 2020, 10:39am UTC](https://discourse.julialang.org/t/incomplete-initialization-control-which-fields-are-initialized-in-new/43452/31 "2020-07-24T10:39:52Z")

</div>

> [@FedericoStra](#):
>
> If you skip the initialization of a field then for sure you are not allocating memory unnecessarily, and in addition you skip also the unneeded assignment.

I’m not totally sure about this. From the example in the documentation:

```julia
julia> struct HasPlain
           n::Int
           HasPlain() = new()
       end

julia> HasPlain()
HasPlain(438103441441)

```

But ok, if it’s only for primitive types that are not heavy, this is no big burden.

And I agree with the rest: being able to leave arbitrary fields uninitialized might the be simplest solution to your case, and also useful in many other cases. I was just commenting on workarounds since that does not seem possible right now.

---

<div class="post-metadata">

**Author:** ![FedericoStra](https://avatars.discourse-cdn.com/v4/letter/f/76d3ee/32.png) [@FedericoStra](https://discourse.julialang.org/u/FedericoStra)\
**Post date:** [July 24, 2020, 10:49am UTC](https://discourse.julialang.org/t/incomplete-initialization-control-which-fields-are-initialized-in-new/43452/32 "2020-07-24T10:49:29Z")

</div>

Regarding your example, since `Int` is “plain data”, the field `n` just retains whatever value was already in that memory location. It doesn’t cause additional memory allocation. If it were `BigInt` or `String`, it would just put an invalid reference, without actually allocating the internal buffers of the (unexistent) `BigInt` or `String`. (I hope!)

```julia
struct HasRef
    n::BigInt
    HasRef() = new()
end

HasRef() # => HasRef(#undef)

```

* * *

> [@heliosdrm](#):
>
> And I agree with the rest: being able to leave arbitrary fields uninitialized might the be simplest solution to your case, and also useful in many other cases.

I feel the same. It just seems like a generally useful feature that currently is only halfway implemented.

> [@heliosdrm](#):
>
> I was just commenting on workarounds since that does not seem possible right now.

Your suggestion is indeed really nice, and is already what I’m doing elsewhere. Basically, depending on the application, I want to code both versions for maximum flexibility.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [July 24, 2020, 10:52am UTC](https://discourse.julialang.org/t/incomplete-initialization-control-which-fields-are-initialized-in-new/43452/33 "2020-07-24T10:52:55Z")

</div>

> [@FedericoStra](#):
>
> I want to code both versions for maximum flexibility

Maybe you already know that intervals are the bottleneck in your code, but in case you are yet to profile, benchmark, and optimize this, I would just define an API and leave the implementation flexible, going with whatever your consider the simplest to start with.

That said, I regularly go down rabbit holes of “doing it right” like this only to discover that they are responsible for 1% of runtime, so who I am to talk 😉

---

<div class="post-metadata">

**Author:** ![FedericoStra](https://avatars.discourse-cdn.com/v4/letter/f/76d3ee/32.png) [@FedericoStra](https://discourse.julialang.org/u/FedericoStra)\
**Post date:** [July 24, 2020, 11:17am UTC](https://discourse.julialang.org/t/incomplete-initialization-control-which-fields-are-initialized-in-new/43452/34 "2020-07-24T11:17:55Z")

</div>

> [@Tamas\_Papp](#):
>
> Maybe you already know that intervals are the bottleneck in your code, but in case you are yet to profile, benchmark, and optimize this, I would just define an API and leave the implementation flexible, going with whatever your consider the simplest to start with.

I know my use case, but I don’t know my library users usecases. That’s why I would like to provide both alternatives. The typed endpoints version is good if you know a priori that you need to work only with intervals of the form `[x,y)`, the other version is better if you need to work with intervals of different kinds and you want them to be of the same type to avoid runtime type-checking.

* * *

Apart from this, while all this brainstorming about this particular example (intervals) is really interesting (there are a loooooot of good ideas to learn from you all!), I don’t think these workarounds really address the question of better controlling an incomplete initialization. Hence…

… I decided to open [this issue](https://github.com/JuliaLang/julia/issues/36789), with the hope that one day we will have keyword arguments for `new(...)`! 🙂

Of course feel free to comment there if you think that it is a good idea or a stupid idea, and if you have the expertise maybe give some hints about how to tackle a possible implementation.

[Previous page](https://discourse.julialang.org/t/incomplete-initialization-control-which-fields-are-initialized-in-new/43452.md?page=1)
