Are structs passed by value or by ref?

Hi there,

like the title, are small structs such as

struct Foo
x::Int64
y::Int64
end

allocated in the stack or in the heap, and whether the are passed by ref or by copy to functions?

Moreover, is there a difference in behaviour between mutable and immutable structs?

2 Likes

Immutable structs are mostly stack allocated, even if it’s fields are pointers. Semantically both mutable and immutable are passed by reference, but for immutables it doesn’t really matter, since they are immutable.
Mutable structs generally stay on the heap, and so they have slower performance, specially if you have an array of them, that is because immutable structs can be stored inline in an array, while mutable structs becomes an array of pointers.
Other threads that went into this are interesting:

7 Likes

Neither: they’re passed by sharing. This is also documented in the manual: Functions · The Julia Language.

8 Likes

Although “pass by sharing” is what most people think—completely reasonably, imo, based on the name—that “pass by reference” means. Unfortunately, “pass by reference”, at least in C++, means something entirely different, which is that you can apply a function to a variable in a calling scope and it can change what value that variable refers to. In sane languages, functions cannot do this at all (macros can though).

16 Likes

For what is worth, Fortran does that as well:

logical function swapnum(i,j)
    integer :: i, j, temp
    temp = i
    i = j
    j = temp
end

program main
    logical :: swapnum, dummy
    integer :: a, b
    a = 10
    b = 20
    dummy = swapnum(a,b) 
    write(*,*)  "a is ", a, " and b is ", b
end program main
% ./ref 
 a is           20  and b is           10

Yeah, it was thought to be a good idea once upon a time, along with dynamically scoped local variables, but these days people have generally recognized that it’s a bad idea as it makes it much harder for a person or compiler to reason about what effect code can have on local variables. This StackOverflow answer has a really good rundown of the meaning and history of these features and terms. These days the most common, standard argument passing behavior is what Lisp (where it originated), Python, Java and Julia all do, which is called “pass by sharing”. A good mental model for this is that all objects are referenced via pointers and those pointers are assigned and passed by value.

12 Likes

More modern Fortran tried to remedy that with the intent syntax for the variables, if one declares those variables as intent(in) you cannot anymore change their values.

1 Like