It’s Base.cconvert(Ref{mystruct}, st) working behind the scenes.
This is probably unsafe. The return value of Base.cconvert is only preserved from GC during this ccall: ccall((:updatestruct, "./libfoo.so"), Ref{mystruct}, (Ref{mystruct},), st). When the ccall returns, ret will store a pointer to the return value of Base.cconvert(Ref{mystruct}, st) and this value may be GC-ed at any time, so it’s not safe to use it in let_c_print_struct2.
If this code works fine, then it’s probably because 1. when Ref{mystruct} is used as a ccall return type, Julia can be notified to preserve a certain value to make its lifetime expands the returned Ref{{mystruct}; 2. you were so lucky that no GC got triggered between these two calls.
I’d say the de facto way of using Ref in ccall is:
function let_c_print_struct2(v_ref::Ref{mystruct})
ccall((:recvstruct, "./libfoo.so"), Int32, (Ptr{mystruct},), v_ref)
end
function let_c_update_struct2()
st_ref = Ref(mystruct(5, 6))
ccall((:updatestruct, "./libfoo.so"), Ptr{mystruct}, (Ptr{mystruct},), st_ref)
let_c_print_struct2(st_ref)
st_ref
end
Now, there is no tmp variable that needs to be created when doing the conversion, so no GC-related segfaults.