# Why \`const\` fields in a \`mutable struct\` instead of \`mutable\` field in ordinary \`struct\`?

**URL:** <https://discourse.julialang.org/t/why-const-fields-in-a-mutable-struct-instead-of-mutable-field-in-ordinary-struct/103454>\
**Category:** Internals & Design\
**Created:** [September 1, 2023, 7:00pm UTC](https://discourse.julialang.org/t/why-const-fields-in-a-mutable-struct-instead-of-mutable-field-in-ordinary-struct/103454 "2023-09-01T19:00:33Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![ForceBru](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/forcebru/32/21389_2.png) [@ForceBru](https://discourse.julialang.org/u/ForceBru)\
**Post date:** [September 1, 2023, 7:00pm UTC](https://discourse.julialang.org/t/why-const-fields-in-a-mutable-struct-instead-of-mutable-field-in-ordinary-struct/103454/1 "2023-09-01T19:00:33Z")

</div>

[The documentation](https://docs.julialang.org/en/v1/manual/types/#Composite-Types) praises immutable structs:

> Composite objects declared with `struct` are immutable; they cannot be modified after construction. This may seem odd at first, but it has several advantages:
> 
> - It can be more efficient. Some structs can be packed efficiently into arrays, and in some cases the compiler is able to avoid allocating immutable objects entirely.
> - It is not possible to violate the invariants provided by the type’s constructors.
> - Code using immutable objects can be easier to reason about.

So, `struct Thing field end` creates a type whose instances will be immutable. You have to explicitly **opt into mutability** using `mutable struct Thing field end`.

The next section of the documentation [says](https://docs.julialang.org/en/v1/manual/types/#Mutable-Composite-Types):

> In cases where one or more fields of an otherwise mutable struct is known to be immutable, one can declare these fields as such using `const`…

This lets me define a `mutable struct` with some `const` fields:

```julia
mutable struct I_am_mut
   mutate_me::Int
   const immutable::Int
end

```

Here, I have to explicitly **opt into immutability**.

* * *

Why this dissonance:

- Structs are fully immutable. I have to opt into _full mutability_ by using `mutable struct`. There’s no partial mutability for `struct`s.
- `mutable struct`s are fully mutable. I can opt into _partial immutability_ by using `const`.

Why not make `struct` “partially mutable”, similar to how `mutable struct` can be partially immutable? Like this:

```julia
struct PartiallyMut
   immutable::Int
   mutable mutate_me::Int
end

```

With this design, mutability is always opt-in, with a gradual scale:

1. `struct` is immutable by default: full immutability.
2. Parts of a `struct` can be explicitly marked `mutable`: partial mutability.
3. The entire struct can be marked mutable with `mutable struct`: full mutability.

Today’s `mutable struct` with `const` fields could’ve been a basic `struct` with `mutable` fields.

This also makes `mutable struct` a generalization of making individual fields `mutable`.

* * *

Does using `mutable struct`s with `const` fields provide additional benefits? Why was such a choice made?

---

<div class="post-metadata">

**Author:** ![jar1](https://avatars.discourse-cdn.com/v4/letter/j/c0e974/32.png) [@jar1](https://discourse.julialang.org/u/jar1)\
**Post date:** [September 1, 2023, 7:01pm UTC](https://discourse.julialang.org/t/why-const-fields-in-a-mutable-struct-instead-of-mutable-field-in-ordinary-struct/103454/2 "2023-09-01T19:01:55Z")

</div>

If you have an immutable struct it’s nice to be able to count on it being immutable.

---

<div class="post-metadata">

**Author:** ![fredrikekre](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fredrikekre/32/1688_2.png) [@fredrikekre](https://discourse.julialang.org/u/fredrikekre)\
**Post date:** [September 1, 2023, 7:16pm UTC](https://discourse.julialang.org/t/why-const-fields-in-a-mutable-struct-instead-of-mutable-field-in-ordinary-struct/103454/3 "2023-09-01T19:16:13Z")

</div>

There was some [discussion on the PR which implemented the new functionality after the same thing was brought up](https://github.com/JuliaLang/julia/pull/43305#issuecomment-985088320).

---

<div class="post-metadata">

**Author:** ![ForceBru](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/forcebru/32/21389_2.png) [@ForceBru](https://discourse.julialang.org/u/ForceBru)\
**Post date:** [September 1, 2023, 7:27pm UTC](https://discourse.julialang.org/t/why-const-fields-in-a-mutable-struct-instead-of-mutable-field-in-ordinary-struct/103454/4 "2023-09-01T19:27:47Z")

</div>

From [this comment](https://github.com/JuliaLang/julia/pull/43305#issuecomment-995270591):

> In contrast, if you start with a mutable struct nothing special is needed to make one field const; you can just disallow mutating it.

Indeed, `const` fields in a `mutable struct` seem to be much simpler to implement.

I also agree with “a mutable struct with some fields marked const is still mutable, while the opposite is not true (immutable struct with mutable field is no longer immutable)”.

* * *

The thing is, I was just trying to make a `struct` with exactly one mutable field and found my code littered with `const` fields which looked ugly to me, so I wondered why it was designed this way and of course didn’t find the PR discussion…

---

<div class="post-metadata">

**Author:** ![contradict](https://avatars.discourse-cdn.com/v4/letter/c/ac91a4/32.png) [@contradict](https://discourse.julialang.org/u/contradict)\
**Post date:** [September 1, 2023, 7:48pm UTC](https://discourse.julialang.org/t/why-const-fields-in-a-mutable-struct-instead-of-mutable-field-in-ordinary-struct/103454/5 "2023-09-01T19:48:57Z")

</div>

An easy way if you just need one field is to use inner mutability:

```julia
julia> struct MyStruct
          immutable::Int
          reference::Ref{Int}
       end

julia> st = MyStruct(7, Ref(8))
MyStruct(7, Base.RefValue{Int64}(8))

julia> st.reference[] = 9
9

julia> st
MyStruct(7, Base.RefValue{Int64}(9))

```

---

<div class="post-metadata">

**Author:** ![Oscar\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oscar_smith/32/25343_2.png) [@Oscar\_Smith](https://discourse.julialang.org/u/Oscar_Smith)\
**Post date:** [September 1, 2023, 8:50pm UTC](https://discourse.julialang.org/t/why-const-fields-in-a-mutable-struct-instead-of-mutable-field-in-ordinary-struct/103454/6 "2023-09-01T20:50:09Z")

</div>

IMO the best short answer is that a `struct` with some fields mutable and some fields `const` is a `mutable struct`. If we had had this feature before 1.0, it seems entirely possible to me that we wouldn’t have `mutable struct` at all and you would have to opt-in to mutability for each mutable field.

---

<div class="post-metadata">

**Author:** ![Elrod](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/elrod/32/22461_2.png) [@Elrod](https://discourse.julialang.org/u/Elrod)\
**Post date:** [September 2, 2023, 12:26am UTC](https://discourse.julialang.org/t/why-const-fields-in-a-mutable-struct-instead-of-mutable-field-in-ordinary-struct/103454/7 "2023-09-02T00:26:05Z")

</div>

Note that is likely worse for performance, as the days won’t be stored inline

---

<div class="post-metadata">

**Author:** ![Zach\_Christensen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/zach_christensen/32/7220_2.png) [@Zach\_Christensen](https://discourse.julialang.org/u/Zach_Christensen)\
**Post date:** [September 2, 2023, 1:51am UTC](https://discourse.julialang.org/t/why-const-fields-in-a-mutable-struct-instead-of-mutable-field-in-ordinary-struct/103454/8 "2023-09-02T01:51:28Z")

</div>

I’m pretty sure this is the main reason but I’m not sure if it’s documented anywhere. It seems like a good performance tip or maybe just part of the const docstring

---

<div class="post-metadata">

**Author:** ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)\
**Post date:** [October 10, 2023, 4:43pm UTC](https://discourse.julialang.org/t/why-const-fields-in-a-mutable-struct-instead-of-mutable-field-in-ordinary-struct/103454/9 "2023-10-10T16:43:39Z")

</div>

There’s one important distinction between a mutable struct with all const fields and an immutable struct. Consider these:

```julia
mutable struct MutableConst
    const f::Int
end

struct Immutable
    f::Int
end

```

The same, right? Not quite:

```julia
julia> MutableConst(1) === MutableConst(1)
false

julia> Immutable(1) === Immutable(1)
true

```

Why? Because the defining property of mutable structures is that they have object identity. What is object identity? It’s whether or not two values of a type with the same content are considered to be the same object or not. If a type has object identity, then they are distinct; if a type lacks object identity, then they are the same. A mutable type must have object identity since otherwise if you modify one copy of the object the other copy will remain unchanged, which immediately reveals that they aren’t actually the same object. Object identity in turn implies that objects are associated with a specific location in memory, since that’s how you ensure that all the references to that same object see the same content. The fact that immutable structs aren’t tied to a specific location in memory is a huge part of why they are so much more optimizable than mutable structs: you’re free to make a copy of an immutable value to pass as an argument or keep in a register—and crucially, it’s semantically _the same object_. If you try to do that with a mutable object you need to make sure your copy stays in sync with “the original”, which can be challenging, if not impossible.

Back to the example. You can only observe the difference between two instances of `MutableConst` by mutation—which you’re not allowed to do—but we still respect their distinct object identity. The defining property of immutable structs, on the other hand is that they lack object identity, so if two immutable objects have the same content, then they are the same value—you’re not allowed to look at their memory address to distinguish them. Whereas with mutable objects, their memory address is the _only_ thing you need to look at to tell if they’re the same object. Note that `===` is not overloadable, so this is a fundamental and unchangeable feature of the language, not how some API happens to be implemented.

Even though `const` fields in mutable structs are a new feature, the same difference can actually be demonstrated in earlier Julia versions with empty structs:

```julia
# Julia 1.0:
julia> mutable struct EmptyMutable end

julia> struct EmptyImmutable end

julia> EmptyMutable() === EmptyMutable()
false

julia> EmptyImmutable() === EmptyImmutable()
true

```

Both structs have no fields which can be modified, so `EmptyMutable`, like `MutableConst`, is a mutable struct with no mutable fields. Even though the object cannot be changed, we respect its object identity and distinguish multiple instances of it. Object identity also sheds some light on why we can have const fields in mutable structs but not mutable fields in immutable structs:

- You can respect object identity while disallowing modification of fields: just allocate a new object each time you construct an instance and consider them the same object if and only if they have the same memory location; you simply disallow changing some of the fields.
- You cannot allow modification of fields without object identity: if you have multiple copies of the same value, they must behave indistinguishably, which is immediately violated if you allow mutation, since you can change one copy while the other copy will remain unchanged.

---

<div class="post-metadata">

**Author:** ![thautwarm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/thautwarm/32/37760_2.png) [@thautwarm](https://discourse.julialang.org/u/thautwarm)\
**Post date:** [November 5, 2023, 3:02am UTC](https://discourse.julialang.org/t/why-const-fields-in-a-mutable-struct-instead-of-mutable-field-in-ordinary-struct/103454/10 "2023-11-05T03:02:41Z")

</div>

Having const fields in mutable structs is fine, as the const keyword placed here is just to tell the compiler/runtime to conform some user-specified restrictions. It is then just syntax sugars.

Having mutable fields in structs can be quite different.

Considering the memory model here, the first to notice is that the mutable fields in structs must have the same memory model as Ref/RefValue fields. Otherwise, mutable fields do not equal to a `RefValue`, and have to be implemented by allowing modifications to a value allocated on stack, which then introduces an user-observable discrepancy when passing arguments by reference/value.

So, a mutable “field” in immutable structs has to be a RefValue with generated getters/setters. Consequently, `getfield` for such structs is not `getfield` any more, but actually `getproperty`. Should `fieldtypes` return the underlying types for mutable fields? What does `fieldoffset` mean for mutable fields? Some reflection-based `Base` functions can get broken and need to be redesigned for the new semantics, but after all the need for mutable fields can be a macro thing? Does it worth? Might not…
