Obviously you could play pointer games. But ultimately, you want your ref to keep z alive, and the way to do this is ref=z. This emits mostly the same code as
ref=reinterpret(Ptr{Int},pointer_from_objref(z))
unsafe_store!(ref, 5)
z
ZInt(5)
It’s just that you don’t have to calculate / look up field offsets and the garbage collector keeps you safe. Afaik there is no advantage of using references; sometimes you might need pointers for performance if you want to store them in a bitstype, but this is always slightly ugly.
mutable struct foo
x::Int64
y::Int64
end
f=foo(1,2)
and I take a reference to f.y which has type Ref{Int64}, how will gc find out that the allocation it needs to keep alive starts 8 bytes prior? (ok, in reality it starts even earlier because of the typetag, but for gc purposes it needs to subtract 8)
That is, the ref would be pointer-sized, and a type encoding offset would be created?
edit: and the concrete type would rather be something like Ref{foo, 2} because we refer to the second field of foo, instead of Ref{Int64, plain}? And maybe something something covariance this should become a subtype of an abstract Ref{Int64, abstract}?