# Is it possible to mutate structs and pass them by reference?

**URL:** <https://forum.crystal-lang.org/t/is-it-possible-to-mutate-structs-and-pass-them-by-reference/7946>\
**Category:** Community\
**Created:** [April 11, 2025, 12:26pm UTC](https://forum.crystal-lang.org/t/is-it-possible-to-mutate-structs-and-pass-them-by-reference/7946 "2025-04-11T12:26:58Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![konovod](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/konovod/32/229_2.png) [@konovod](https://forum.crystal-lang.org/u/konovod)\
**Post date:** [April 11, 2025, 12:26pm UTC](https://forum.crystal-lang.org/t/is-it-possible-to-mutate-structs-and-pass-them-by-reference/7946/1 "2025-04-11T12:26:58Z")

</div>

Ok, this topic name is fishy - it’s not about questions but about answers))

I’ve made a simple wrapper that holds a pointer to struct inside and forwards all setters and getters to it. This way you can do  
`some_struct.header.id += 1`  
or  
`increment_position(my_struct)`  
without a fear that a copy will be modified.

You can check it here: [GitHub - konovod/ref\_record](https://github.com/konovod/ref_record)

There is still one big drawback - a need to manually mark fields that contain struct to make it possible to correctly nest them. Hopefully it is possible to solve it with some clever trick.

---

<div class="post-metadata">

**Author:** ![straight-shoota](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/straight-shoota/32/36_2.png) [@straight-shoota](https://forum.crystal-lang.org/u/straight-shoota)\
**Post date:** [April 11, 2025, 12:48pm UTC](https://forum.crystal-lang.org/t/is-it-possible-to-mutate-structs-and-pass-them-by-reference/7946/2 "2025-04-11T12:48:19Z")

</div>

What’s the point, though?  
Reference semantics are much better expressed in a `class`. That’s much cleaner and has fewer quirks than mutating structs.

If the goal is to avoid allocations, you can put the class instance in non-heap memory, for example with [`Reference.unsafe_construct`](https://crystal-lang.org/api/1.16.0/Reference.html#unsafe_construct(address:Pointer,*args,**opts):self-class-method) (experimental, discussion in [#13481](https://github.com/crystal-lang/crystal/issues/13481)).

---

<div class="post-metadata">

**Author:** ![konovod](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/konovod/32/229_2.png) [@konovod](https://forum.crystal-lang.org/u/konovod)\
**Post date:** [April 11, 2025, 1:09pm UTC](https://forum.crystal-lang.org/t/is-it-possible-to-mutate-structs-and-pass-them-by-reference/7946/3 "2025-04-11T13:09:06Z")

</div>

Classes has overhead (one pointer per instance, i think?), so they are bad in two cases:

- array of small structs (where even one pointer will significantly increase size)
- when struct layout is defined elsewhere (lowlevel protocols, interfacing with external libs, also mcu SDK)

So while `Reference.unsafe_construct` is awesome and this wrapper is solving similar problem from another end, I don’t think Reference would replace all uses of mutable structs.

---

<div class="post-metadata">

**Author:** ![ysbaddaden](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/ysbaddaden/32/2252_2.png) [@ysbaddaden](https://forum.crystal-lang.org/u/ysbaddaden)\
**Post date:** [April 11, 2025, 1:41pm UTC](https://forum.crystal-lang.org/t/is-it-possible-to-mutate-structs-and-pass-them-by-reference/7946/4 "2025-04-11T13:41:46Z")

</div>

Oh, nice. A zero runtime cost abstraction, and we don’t have to deal with the `Pointer`. Still dangerous as we can easily pass it around and forget it might point to unsafe memory 😅

I’ll note that we can ~~abuse~~ leverage the `method_missing` macro to wrap any `struct`. See this [Carcin](https://carc.in/#/r/hv4s) PoC 😈

---

<div class="post-metadata">

**Author:** ![konovod](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/konovod/32/229_2.png) [@konovod](https://forum.crystal-lang.org/u/konovod)\
**Post date:** [April 11, 2025, 9:07pm UTC](https://forum.crystal-lang.org/t/is-it-possible-to-mutate-structs-and-pass-them-by-reference/7946/5 "2025-04-11T21:07:34Z")

</div>

The `method_missing` approach is elegant, but the problem is that it doesn’t solve situations when structs are nested:

> **[Carcin](https://carc.in/#/r/hv6b)**

```auto
line = Line.new(Point.new(1, 2), Point.new(3, 4))
 
ref = Ref.new(pointerof(line))
p ref.start.x
ref.start.x = 0
p ref.start.x

```

---

<div class="post-metadata">

**Author:** ![ysbaddaden](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/ysbaddaden/32/2252_2.png) [@ysbaddaden](https://forum.crystal-lang.org/u/ysbaddaden)\
**Post date:** [April 12, 2025, 9:32pm UTC](https://forum.crystal-lang.org/t/is-it-possible-to-mutate-structs-and-pass-them-by-reference/7946/6 "2025-04-12T21:32:31Z")

</div>

Yeah, you must explicitly Ref(Point) too, which ref record does for you.
