I think it’s helpful to think it like this:
- classes are reference types: they are a pointer to the actual data
- structs are value types: their data is inlined
What that means is when you do:
x = SomeClass.new
x
will be a pointer pointing to the data that SomeClass
holds. Something like:
x = pointer -> [...data (instance vars)...]
and [...data...]
is allocated on the heap.
If you have a type that has an instance variable of type SomeClass
, that instance variable is also a pointer to the data. When you assign x
to that instance variable that pointer is copied.
Note that when you do x = SomeClass.new
, the pointer for x
is stored on the stack.
With a struct, the data is inlined:
x = SomeStruct.new
so essentially x is the data:
x = [...data...]
and x
is allocated on the stack.
If you have a type with an instance variable of type SomeStruct
, that instance variable will not be a pointer to the data but it will have all the space for the struct. When you assign x
to that instance variable, the data will be copied to that space.
So let’s say SomeClass
has an instance variable s
of type SomeStruct
, and SomeStruct
has two instance variables of type Int32
. You do:
c = SomeClass.new
c.s = SomeStruct.new
it will be:
c = pointer -> [s = [x: Int32, y : Int32]]
note that everything after ->
is in heap memory, which in this case will be 8 bytes.
When you do c.s = SomeStruct.new
, that entire data is moved (copied) into the heap.
If it’s the other way around, and SomeStruct
has an instance variable of type SomeClass
, which in turn has two integers:
s = SomeStruct.new
s.c = SomeClass.new
it will be like this:
s = [c = pointer -> [x: Int32, y : Int32]]
Note that s
in this case has its data inlined, and because it only holds a SomeClass
, which is represented as a pointer, s
's data is just a pointer. The data for that pointer always lives on the heap.
When you do:
c = SomeClass.new
s.c = c
the pointer for c
, which lives in the stack (but the data lives in the heap) is copied from the stack to the struct (which in this case also lives in the stack).
I hope this is clear!