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

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

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.

1 Like

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 (experimental, discussion in #13481).

1 Like

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.

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 :sweat_smile:

I’ll note that we can abuse leverage the method_missing macro to wrap any struct. See this Carcin PoC :smiling_face_with_horns:

2 Likes

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

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

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