# ANN: LazilyInitializedFields.jl - Handling lazily initialized fields in a consistent way

**URL:** <https://discourse.julialang.org/t/ann-lazilyinitializedfields-jl-handling-lazily-initialized-fields-in-a-consistent-way/47770>\
**Category:** Community\
**Created:** [October 5, 2020, 7:43am UTC](https://discourse.julialang.org/t/ann-lazilyinitializedfields-jl-handling-lazily-initialized-fields-in-a-consistent-way/47770 "2020-10-05T07:43:01Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [October 5, 2020, 7:43am UTC](https://discourse.julialang.org/t/ann-lazilyinitializedfields-jl-handling-lazily-initialized-fields-in-a-consistent-way/47770/1 "2020-10-05T07:43:01Z")

</div>

Hi,

I created a small package to handle lazily initialized fields. A lazily initialized field is a field in a struct that does not get initialized on the creation of the struct but at some later point. While it is a good idea, in general, to fully initialize structs, there are times where for e.g. performance reason you want to only initialize certain fields when they are actually needed. I recently had such a situation and I wasn’t 100% satisfied with the solutions Julia itself provided, so I made this package.

Installation, examples, and documentation can be found at [LazilyInitializedFields.jl](https://kristofferc.github.io/LazilyInitializedFields.jl/) (thanks PkgPkage.jl). It goes through how you use the package and contrast it with some of the other common ways of dealing with lazy fields in Julia (using a `Ref` or using a `Union` field) and why these didn’t fulfill the requirements I had. The page also shows how the package is implemented which some people might find interesting.

Note that the package is still in the registration process so has to be added by URL (as shown in the docs).

Best,  
Kristoffer

---

<div class="post-metadata">

**Author:** ![ric.cioffi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ric.cioffi/32/18373_2.png) [@ric.cioffi](https://discourse.julialang.org/u/ric.cioffi)\
**Post date:** [October 5, 2020, 10:21am UTC](https://discourse.julialang.org/t/ann-lazilyinitializedfields-jl-handling-lazily-initialized-fields-in-a-consistent-way/47770/2 "2020-10-05T10:21:51Z")

</div>

Nice! That seems extremely useful.

I only gave it a very quick look but from reading the docs it seems to me that all lazily initialized structs are mutable:

```julia
using LazilyInitializedFields

julia> @lazy struct Foo
           a::Int
           @lazy b::Int
       end

julia> f = Foo(1, uninit)
Foo(1, uninit)

julia> ismutable(f)
true

```

in which case it might make sense to make the `@lazy` macro available for `mutable struct`s only

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [October 5, 2020, 11:22am UTC](https://discourse.julialang.org/t/ann-lazilyinitializedfields-jl-handling-lazily-initialized-fields-in-a-consistent-way/47770/3 "2020-10-05T11:22:43Z")

</div>

> [@ric.cioffi](#):
>
> I only gave it a very quick look but from reading the docs it seems to me that all lazily initialized structs are mutable:

They are mutable from julias point of view but the standard way of mutating them is disabled.

```julia
julia> f.a = 2
ERROR: setproperty! for struct of type `Foo` has been disabled

```

You can of course get around this with `setfield!` but the point is that with standard usage they act non-mutable so you won’t mutate it by accident.

---

<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:** [October 5, 2020, 11:29am UTC](https://discourse.julialang.org/t/ann-lazilyinitializedfields-jl-handling-lazily-initialized-fields-in-a-consistent-way/47770/4 "2020-10-05T11:29:50Z")

</div>

Nice package. Kudos for the excellent docs.

---

<div class="post-metadata">

**Author:** ![ric.cioffi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ric.cioffi/32/18373_2.png) [@ric.cioffi](https://discourse.julialang.org/u/ric.cioffi)\
**Post date:** [October 5, 2020, 11:36am UTC](https://discourse.julialang.org/t/ann-lazilyinitializedfields-jl-handling-lazily-initialized-fields-in-a-consistent-way/47770/5 "2020-10-05T11:36:49Z")

</div>

> [@kristoffer.carlsson](#):
>
> They are mutable from julias point of view but the standard way of mutating them is disabled.

Will this impact performance relative to using immutable structs?

> [@kristoffer.carlsson](#):
>
> You can of course get around this with `setfield!` but the point is that with standard usage they act non-mutable so you won’t mutate it by accident.

Alright, that makes sense.  
~~On another note though, mutating is then disabled for lazily initialized `mutable` structs as well (and that is true for all fields, not just the lazily initialized ones), which effectively makes them immutable with standard usage.  
Not sure if that’s feasible but it might be desirable to allow standard mutation for lazily initialized mutable structs.~~

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [October 5, 2020, 11:39am UTC](https://discourse.julialang.org/t/ann-lazilyinitializedfields-jl-handling-lazily-initialized-fields-in-a-consistent-way/47770/6 "2020-10-05T11:39:58Z")

</div>

> [@ric.cioffi](#):
>
> Will this impact performance relative to using immutable structs?

Yes, since they are mutable they will no longer be stored in-line in e.g. `Vector`s. I’ll add a snippet in the docs about this.

> [@ric.cioffi](#):
>
> Not sure if that’s feasible but it might be desirable to allow standard mutation for lazily initialized mutable structs.

I think that should already work:

```julia
julia> @lazy mutable struct Foo
           a::Int
           @lazy b::Int
       end

julia> f = Foo(1, uninit)
Foo(1, uninit)

julia> f.a = 2
2

julia> f.b = 3
3

```

---

<div class="post-metadata">

**Author:** ![ric.cioffi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ric.cioffi/32/18373_2.png) [@ric.cioffi](https://discourse.julialang.org/u/ric.cioffi)\
**Post date:** [October 5, 2020, 11:43am UTC](https://discourse.julialang.org/t/ann-lazilyinitializedfields-jl-handling-lazily-initialized-fields-in-a-consistent-way/47770/7 "2020-10-05T11:43:38Z")

</div>

> [@kristoffer.carlsson](#):
>
> Yes, since they are mutable they will no longer be stored in-line in e.g. `Vector` s. I’ll add a snippet in the docs about this.

Sounds great. I’m guessing there is no way to actually make them actual immutables?

> [@kristoffer.carlsson](#):
>
> I think that should already work:

Yes, sorry. I realized that was true as soon as I posted it

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [October 5, 2020, 11:44am UTC](https://discourse.julialang.org/t/ann-lazilyinitializedfields-jl-handling-lazily-initialized-fields-in-a-consistent-way/47770/8 "2020-10-05T11:44:24Z")

</div>

> [@ric.cioffi](#):
>
> Sounds great. I’m guessing there is no way to actually make them actual immutables?

No, since (pretty much by definition) you want to mutate the fields after the creation of the object.

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [October 5, 2020, 1:18pm UTC](https://discourse.julialang.org/t/ann-lazilyinitializedfields-jl-handling-lazily-initialized-fields-in-a-consistent-way/47770/9 "2020-10-05T13:18:58Z")

</div>

Here is the new caveat section: [LazilyInitializedFields.jl](https://kristofferc.github.io/LazilyInitializedFields.jl/#caveats)

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [October 5, 2020, 2:03pm UTC](https://discourse.julialang.org/t/ann-lazilyinitializedfields-jl-handling-lazily-initialized-fields-in-a-consistent-way/47770/10 "2020-10-05T14:03:56Z")

</div>

I think it might be nice to provide a way to make the struct immutable and then users can use things like [https://github.com/jw3126/Setfield.jl](https://github.com/jw3126/Setfield.jl) to update values without mutation if they desire it.

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [October 5, 2020, 2:11pm UTC](https://discourse.julialang.org/t/ann-lazilyinitializedfields-jl-handling-lazily-initialized-fields-in-a-consistent-way/47770/11 "2020-10-05T14:11:36Z")

</div>

I personally don’t think that would be too useful because it is likely the object will be stored somewhere (maybe in multiple places) and it is likely you do in fact want to change the object itself, not just get a new, initialized object.

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [October 5, 2020, 2:23pm UTC](https://discourse.julialang.org/t/ann-lazilyinitializedfields-jl-handling-lazily-initialized-fields-in-a-consistent-way/47770/12 "2020-10-05T14:23:00Z")

</div>

I personally think that my desire to partially initialize a struct often doesn’t have much to do if it’s mutable or not, but maybe that’s just me. I find Setfield.jl works quite nice for me when I want to update immutable structs.

* * *

**Edit:**

I should say, regardless this looks really cool and I think I’m likely to make use of it sometime!

---

<div class="post-metadata">

**Author:** ![cstjean](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cstjean/32/1444_2.png) [@cstjean](https://discourse.julialang.org/u/cstjean)\
**Post date:** [October 5, 2020, 2:46pm UTC](https://discourse.julialang.org/t/ann-lazilyinitializedfields-jl-handling-lazily-initialized-fields-in-a-consistent-way/47770/13 "2020-10-05T14:46:51Z")

</div>

I believe for immutable structs you could use `b::Ref{Union{Uninitialized, T}}` + custom `getproperty` like you already have, no? Now that non-isbits structs are often allocated inline, it could have good performance in spite of the Ref.

I like the idea behind the package. I can see myself using it for memoizing computations that may not happen.

```julia
struct MyMat
    A
    @lazy det=LinearAlgebra.det(A)
end

```

would be a nice syntax for it.

I hope eventually someone will collect all these tricks into one big macro.

```julia
@fancy mutable struct Foo{T}
   a::T   
   @lazy b
   @read_only c
   @cached z=det(a)
end

```

etc. Common Lisp’s CLOS macro was ridiculous, but it had some really interesting parts.

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [October 5, 2020, 2:47pm UTC](https://discourse.julialang.org/t/ann-lazilyinitializedfields-jl-handling-lazily-initialized-fields-in-a-consistent-way/47770/14 "2020-10-05T14:47:29Z")

</div>

> [@Mason](#):
>
> I personally think that my desire to partially initialize a struct often doesn’t have much to do if it’s mutable or not, but maybe that’s just me.

Probably not just you :). It could be possible to have non-mutating versions of `@init!`, `@uninit!` that returns the modified struct and have a `@staticlazy` or something that doesn’t convert to a `mutable struct`. I might get around to it some point but if someone needs some PRs for hacktoberfest feel free to work on it 🙂

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [October 5, 2020, 2:50pm UTC](https://discourse.julialang.org/t/ann-lazilyinitializedfields-jl-handling-lazily-initialized-fields-in-a-consistent-way/47770/15 "2020-10-05T14:50:29Z")

</div>

> [@cstjean](#):
>
> I believe for non-mutable struct you could use `b::Ref{Uninitialized, T}` + custom `getproperty` like you already have, no?

Hm, yeah, that might be a better implementation than what I currently have. I’ll have to try it out.

> [@cstjean](#):
>
> I can see myself using it for memoizing computations that may not happen.

That’s pretty cool with the initialization next to the object.

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [October 5, 2020, 3:39pm UTC](https://discourse.julialang.org/t/ann-lazilyinitializedfields-jl-handling-lazily-initialized-fields-in-a-consistent-way/47770/16 "2020-10-05T15:39:11Z")

</div>

> [@cstjean](#):
>
> I believe for immutable structs you could use `b::Ref{Union{Uninitialized, T}}` + custom `getproperty` like you already have, no?

One annoyance is:

```julia
julia> struct A
           a::Int
           b::Ref{Union{Nothing, Int}}
       end

julia> struct B{T}
           a::T
           b::Union{Nothing, Int}
       end

julia> struct C{T}
           a::T
           b::Ref{Union{Nothing, Int}}
       end

julia> A(1, 2)
A(1, Base.RefValue{Union{Nothing, Int64}}(2))

julia> B(1, 2)
B{Int64}(1, 2)

julia> C(1, 2)
ERROR: MethodError: no method matching C(::Int64, ::Int64)
Closest candidates are:
  C(::T, ::Ref{Union{Nothing, Int64}}) where T at REPL[3]:2
Stacktrace:
 [1] top-level scope at REPL[6]:1

julia> C{Int}(1,2)
C{Int64}(1, Base.RefValue{Union{Nothing, Int64}}(2))

```

Ref [Autogenerate `(::Type{Foo})(x::T, y) where T` constructor for type Foo{T} · Issue #35053 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/35053). I could try generate that constructor myself.

---

<div class="post-metadata">

**Author:** ![rfourquet](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rfourquet/32/3610_2.png) [@rfourquet](https://discourse.julialang.org/u/rfourquet)\
**Post date:** [October 5, 2020, 5:04pm UTC](https://discourse.julialang.org/t/ann-lazilyinitializedfields-jl-handling-lazily-initialized-fields-in-a-consistent-way/47770/17 "2020-10-05T17:04:04Z")

</div>

Nice package! Concerning the " Other methods of achieving lazily initialized fields" with “Use a `::Ref{T}` field”: I might misunderstand, but this method doesn’t fail 5), i.e. the struct can be immutable?

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [October 5, 2020, 5:10pm UTC](https://discourse.julialang.org/t/ann-lazilyinitializedfields-jl-handling-lazily-initialized-fields-in-a-consistent-way/47770/18 "2020-10-05T17:10:37Z")

</div>

Thanks, that’s indeed true.

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [October 5, 2020, 7:35pm UTC](https://discourse.julialang.org/t/ann-lazilyinitializedfields-jl-handling-lazily-initialized-fields-in-a-consistent-way/47770/19 "2020-10-05T19:35:41Z")

</div>

> [@cstjean](#):
>
> I believe for immutable structs you could use `b::Ref{Union{Uninitialized, T}}` + custom `getproperty` like you already have, no?

Another annoyance, `Nothing` is special:

```julia
julia> struct A
           b::Ref{Union{Nothing, Int}}
       end

julia> struct Uninitialized end

julia> struct B
           b::Ref{Union{Uninitialized, Int}}
       end

julia> A(2.0)
A(Base.RefValue{Union{Nothing, Int64}}(2))

julia> B(2.0)
ERROR: MethodError: Cannot `convert` an object of type
  Float64 to an object of type
  Union{Uninitialized, Int64}
Closest candidates are:
  convert(::Type{T}, ::T) where T at essentials.jl:205

```

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [October 5, 2020, 8:16pm UTC](https://discourse.julialang.org/t/ann-lazilyinitializedfields-jl-handling-lazily-initialized-fields-in-a-consistent-way/47770/20 "2020-10-05T20:16:38Z")

</div>

> [@cstjean](#):
>
> I believe for immutable structs you could use `b::Ref{Union{Uninitialized, T}}` + custom `getproperty` like you already have, no?

I implemented it for immutable structs without type parameters at least: [add an optimization for immutable structs without type arguments by KristofferC · Pull Request #1 · KristofferC/LazilyInitializedFields.jl · GitHub](https://github.com/KristofferC/LazilyInitializedFields.jl/pull/1).

```julia
julia> using LazilyInitializedFields

julia> @lazy struct Foo
           a::Int
           @lazy b::Int
       end

julia> f = Foo(1, uninit)
Foo(1, uninit)

julia> ismutable(f)
false

julia> @init! f.b = 2
2

julia> f.b
2

julia> @uninit! f.b
uninit

julia> @isinit f.b
false

```

I want to write some benchmarks first before merging just to see that things look ok with it though.

[Next page](https://discourse.julialang.org/t/ann-lazilyinitializedfields-jl-handling-lazily-initialized-fields-in-a-consistent-way/47770.md?page=2)
