# Can a method push! to a Vector that is a field in a struct?

**URL:** https://discourse.julialang.org/t/can-a-method-push-to-a-vector-that-is-a-field-in-a-struct/75964
**Category:** General Usage
**Tags:** question
**Created:** [February 7, 2022, 6:31pm UTC](https://discourse.julialang.org/t/can-a-method-push-to-a-vector-that-is-a-field-in-a-struct/75964 "2022-02-07T18:31:44Z")
**Posts on this page:** 6
**Page:** 1

<div class="post-metadata">

### Author: ![dmbates](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dmbates/32/44_2.png) [@dmbates](https://discourse.julialang.org/u/dmbates)
#### Post date: [February 7, 2022, 6:31pm UTC](https://discourse.julialang.org/t/can-a-method-push-to-a-vector-that-is-a-field-in-a-struct/75964/1 "2022-02-07T18:31:44Z")

</div>

In [https://github.com/dmbates/Wordlegames.jl](https://github.com/dmbates/Wordlegames.jl) I use a struct to represent the state of a Wordle (or similar) game. I am thinking of recording the history of guesses and scores from these guess as fields which will be `Vector{<:Integer}`. (In Wordle “Hard Mode” the guess must always be from the current target pool and it can be represented as an index into the initial target pool. Similarly a score can be regarded as a number in base-3.)

Because Wordle allows only 6 guesses, the vectors could be fixed-length. But I would prefer to avoid a restriction like that in the design, because I want to analyze related games that may need more than 6 guesses. Also, it would be convenient to `empty!` this container at the beginning of the game and `push!` results onto it so it is easy to determine things like what the last guess was.

If I declare the field to be, say, `Vector{Int}` and initialize it to, say, `sizehint!(Int[], 10)`, can I safely push! to it even though it is a field in a `struct`. The situation I am trying to avoid is `push!` causing a re-allocate and copy when the available storage for the vector is exhausted. It is fine to change the contents of a field in a struct but not the location.

---

<div class="post-metadata">

### Author: ![giordano](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giordano/32/2166_2.png) [@giordano](https://discourse.julialang.org/u/giordano)
#### Post date: [February 7, 2022, 6:38pm UTC](https://discourse.julialang.org/t/can-a-method-push-to-a-vector-that-is-a-field-in-a-struct/75964/2 "2022-02-07T18:38:03Z")

</div>

If the question is whether you can mutate fields of an immutable struct, then the answer is yes, if their type is mutable, that’s totally fine:

```julia
julia> struct Foo
           x::Vector{Int}
           y::Int
       end

julia> a = Foo(Int[], 2)
Foo(Int64[], 2)

julia> push!(a.x, 42)
1-element Vector{Int64}:
 42

julia> a
Foo([42], 2)

```

What you can’t do is to rebind the fields to something else with the assignment operation:

```julia
julia> a.x = [17]
ERROR: setfield!: immutable struct of type Foo cannot be changed
Stacktrace:
 [1] setproperty!(x::Foo, f::Symbol, v::Vector{Int64})
   @ Base ./Base.jl:43
 [2] top-level scope
   @ REPL[5]:1

julia> a.y = 5
ERROR: setfield!: immutable struct of type Foo cannot be changed
Stacktrace:
 [1] setproperty!(x::Foo, f::Symbol, v::Int64)
   @ Base ./Base.jl:43
 [2] top-level scope
   @ REPL[6]:1

```

You have to go through in-place operations, like `empty!` and then `push!`/`append!`, for the fields which are mutable, in this case only `x`:

```julia
julia> empty!(a.x)
Int64[]

julia> push!(a.x, 17)
1-element Vector{Int64}:
 17

julia> a
Foo([17], 2)

```

This is also mentioned in the [documentation of types](https://docs.julialang.org/en/v1/manual/types/#Composite-Types)

> An immutable object might contain mutable objects, such as arrays, as fields. Those contained objects will remain mutable; only the fields of the immutable object itself cannot be changed to point to different objects.

---

<div class="post-metadata">

### Author: ![dmbates](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dmbates/32/44_2.png) [@dmbates](https://discourse.julialang.org/u/dmbates)
#### Post date: [February 7, 2022, 6:53pm UTC](https://discourse.julialang.org/t/can-a-method-push-to-a-vector-that-is-a-field-in-a-struct/75964/3 "2022-02-07T18:53:33Z")

</div>

Thanks for the reply. I may not have phrased it well but I realize that I can change the contents of a field but I can’t rebind it. What I was asking specifically is what happens if `push!` causes the rebinding behind the scenes?

As I understand it, when using a Vector as a stack or a deque the memory for the vector is over-allocated initially so that elements can be pushed on to the end. The `sizehint!` function allows the programmer to give hints on the initial size. But if you try to `push!` beyond the allocated memory the operation has to allocate a larger chunk and copy the current contents into the new location. At least, that is how I understand it works.

So there could be a situation where several `push!` calls are benign but then one comes along that causes a reallocation and hence a rebinding. What happens in that situation?

---

<div class="post-metadata">

### Author: ![palday](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/palday/32/12640_2.png) [@palday](https://discourse.julialang.org/u/palday)
#### Post date: [February 7, 2022, 7:15pm UTC](https://discourse.julialang.org/t/can-a-method-push-to-a-vector-that-is-a-field-in-a-struct/75964/4 "2022-02-07T19:15:09Z")

</div>

I think the confusion is that the Julia-level `Vector` is not rebound when `push!` does something (IIUC). In other words, `push!` might re-allocate a new contiguous block of memory, but that only changes its internal pointer to that memory, not the Julia-level binding to your `Vector`.

---

<div class="post-metadata">

### Author: ![lawless-m](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lawless-m/32/30869_2.png) [@lawless-m](https://discourse.julialang.org/u/lawless-m)
#### Post date: [February 7, 2022, 8:16pm UTC](https://discourse.julialang.org/t/can-a-method-push-to-a-vector-that-is-a-field-in-a-struct/75964/5 "2022-02-07T20:16:35Z")

</div>

One might answer your question with a question

_What happened when you tried it?_

```julia
struct Foo
v
end

f = Foo(Int[])

for i in 1:1_000_000
    push!(f.v, i)
end

```

---

<div class="post-metadata">

### Author: ![dmbates](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dmbates/32/44_2.png) [@dmbates](https://discourse.julialang.org/u/dmbates)
#### Post date: [February 7, 2022, 8:39pm UTC](https://discourse.julialang.org/t/can-a-method-push-to-a-vector-that-is-a-field-in-a-struct/75964/6 "2022-02-07T20:39:38Z")

</div>

I was planning to try it but I thought I would ask here first in case someone knew the answer immediately.

It turns out that my idea of how a Vector is implemented was wrong. I hadn’t realized that there was the extra level of indirection that @palday mentioned.
