# Using Accessors to mutate an incomplete initialized struct

**URL:** <https://discourse.julialang.org/t/using-accessors-to-mutate-an-incomplete-initialized-struct/61917>\
**Category:** General Usage\
**Tags:** question, bug\
**Created:** [May 27, 2021, 12:29pm UTC](https://discourse.julialang.org/t/using-accessors-to-mutate-an-incomplete-initialized-struct/61917 "2021-05-27T12:29:12Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![t-bltg](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/t-bltg/32/25526_2.png) [@t-bltg](https://discourse.julialang.org/u/t-bltg)\
**Post date:** [May 27, 2021, 12:29pm UTC](https://discourse.julialang.org/t/using-accessors-to-mutate-an-incomplete-initialized-struct/61917/1 "2021-05-27T12:29:13Z")

</div>

Hi,  
I am trying to write a method for finalizing incomplete initialization of a struct. I want to avoid using a mutable struct.  
I found [Setfield.jl](https://github.com/jw3126/Setfield.jl) or [Accessors.jl](https://github.com/JuliaObjects/Accessors.jl) which seem to fulfill my requirements, but it fails somehow.  
Is there a simple fix for this or is there an alternative ?

Here is a **mwe.jl** :

```julia
using Accessors

struct Foo{T, N}
  a::Array{T, N}
  b::Int

  # incomplete ctor & finalize
  Foo(a::Array{T, N}) where {T, N} = begin
    println("incomplete")
    this = new{T, N}(a)
    return complete(this)
  end

  # forward ctor
  Foo(a::Array{T, N}, args...) where {T, N} = begin
    println("forward $(args)")
    return new{T, N}(a, args...)
  end
end

complete(f::Foo{T, N}) where {T, N} = begin
  @set f.b = 100
  @show f.b # <== something is wrong
  return f
end

function main()
  @show Foo(ones(Float32, (1, 1)), 50) # OK
  @show Foo(ones(Float32, (1, 2))) # NOK
  return
end

main()

```

Output:

```bash
$ julia mwe.jl
forward (50,)
Foo(ones(Float32, (1, 1)), 50) = Foo{Float32, 2}(Float32[1.0], 50)
incomplete
forward (100,)
f.b = 0
Foo(ones(Float32, (1, 2))) = Foo{Float32, 2}(Float32[1.0 1.0], 0)

```

---

<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:** [June 9, 2021, 2:28pm UTC](https://discourse.julialang.org/t/using-accessors-to-mutate-an-incomplete-initialized-struct/61917/2 "2021-06-09T14:28:26Z")

</div>

Sorry this might be a bit late, but a few things. First, try not to do this! there is probably a better way than having undefined fields. 🙂

Second, you are not actually assigning a new `f`. But this version gives the result you expect:

```julia
complete(f::Foo{T, N}) where {T, N} = begin
  f = @set f.b = 100
  @show f.b # <== should be 100 now
  return f
end

```

Remember these are immutable objects.

---

<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:** [June 9, 2021, 3:04pm UTC](https://discourse.julialang.org/t/using-accessors-to-mutate-an-incomplete-initialized-struct/61917/3 "2021-06-09T15:04:28Z")

</div>

[LazilyInitializedFields.jl](https://kristofferc.github.io/LazilyInitializedFields.jl/) might be useful.

---

<div class="post-metadata">

**Author:** ![t-bltg](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/t-bltg/32/25526_2.png) [@t-bltg](https://discourse.julialang.org/u/t-bltg)\
**Post date:** [June 29, 2021, 1:47pm UTC](https://discourse.julialang.org/t/using-accessors-to-mutate-an-incomplete-initialized-struct/61917/4 "2021-06-29T13:47:39Z")

</div>

@kristoffer.carlsson thanks, LazilyInitializedFields perfectly solves the issue.

Updated / working code for posterity:

```julia
using LazilyInitializedFields

@lazy struct Foo{T, N}
  a::Array{T, N}
  @lazy b::Int

  # incomplete ctor & finalize
  Foo(a::Array{T, N}) where {T, N} = begin
    println(">> incomplete")
    this = new{T, N}(a)
    return complete(this)
  end

  # forward ctor
  Foo(a::Array{T, N}, args...) where {T, N} = begin
    println(">> forward $(length(args)) $args")
    return new{T, N}(a, args...)
  end
end

complete(f::Foo{T, N}) where {T, N} = begin
  @init! f.b = 100
  @show f.b
  return f
end

function main()
  @show Foo(ones(Float32, (1, 1)), 50)
  @show Foo(ones(Float32, (1, 2)))
  return
end

main()

```

Output:

```bash
$ julia mwe.jl
>> forward 1 (50,)
Foo(ones(Float32, (1, 1)), 50) = Foo{Float32, 2}(Float32[1.0], 50)
>> incomplete
f.b = 100
Foo(ones(Float32, (1, 2))) = Foo{Float32, 2}(Float32[1.0 1.0], 100)

```
