Passing a non-mutable argument by value or by reference?

A function can generally be defined to receive parameters by value or by reference. If we want to mutate an object inside the function and have those changes reflected outside the function, then it must be passed by reference.

If we don’t want to mutate the object then we can choose between passing by value or by reference. The choice, in my experience, is based on whether or not it’s expensive to copy the object. If it’s cheaper to copy than to deal with the reference’s indirection – pass by value, else – pass by reference.

1) Are there any other considerations that should be taken into account?

2) Wouldn’t a compiler be better suited to make this choice instead of the programmer? Why, or why not?

To illustrate question 2, the programmer could simply indicate whether they intend to mutate an argument or not. If an argument will be mutated then it must be passed by reference. If it won’t be mutated, then the compiler can choose between passing by value or by reference – whichever is faster.

3) Do you see any pitfalls in this approach to language/compiler design?