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?
Be careful. If I define (C type syntax for familiarity):

int var;

void f(const int x)
{
      ...
      var = ...;
      ...
      /* use */ ... x ...
      ...
}


Now go f(var). If pass by value, f uses the original value (at the call); with pass by reference, the value asigned in f. The language should specify which one. Only if the compiler can prove it makes no difference can it decide (and for that, it has to know all programs calling f, or forbid changing global variables).

I'd give one option, just for clarity of specification.