I reason I think this discussion is ever a problem is because in C++ "pass-by-value" has an extra meaning: that a deep copy occurs. There's no precise term for this, so people started (incorrectly) using "pass-by-reference" to talk about parameters that don't get deep copied. After all, in languages that do it right (Java, Ruby, Python, CL) there's only one parameter passing technique, and therefore no reason to make the distinction.
There is a precise term for that and you said it - pass-by-value. Recall that somewhere each language turns into assembly and that in order to pass a value to a subroutine you must either place values into registers or push the data of the object you are passing onto the stack. Passing by value is desirable if you want to make sure that your local value is not modified. This gives the called function the freedom to modify it without worrying about side effects and without worrying about explicitly calling a copy constructor. Pass-by-reference comes from C++'s pass by reference, which is really just some sugar around passing a pointer by value and referencing it with the * operator in the function body (hence reference passing).
I disagree that there is a right or wrong to this - C++ was made to be a generic programming language and thus gives many options to the programmer. If by "do it right" you meant "hide all options except the one most commonly used" okay. Otherwise I strongly disagree with that sentence especially because I use different kinds of "pass-by" whenever I program in C++ and will be using rvalue reference from the C++0x. Different languages suit different needs.
Well the term is not very precise if the way that you're using it and the way the article is using it are completely different. The article makes it clear that the term "pass-by-value" refers to the fact that the callers' references cannot be unseated by the function call; but it does not mean deep copies are made, like by copy constructor, hence that's why it applies to Java. Allow me to illustrate:
vector<int> numbers;
void f(vector<int> args);
Due to C++'s copying, args[0] has a different address than numbers[0], because a deep copy of the vector was made. As the article states, this is not what pass-by-value is referring to, otherwise it would be false that Java / Python / Ruby et al are pass-by-value. So I disagree that the terms are clear, but rather that there is confusion around these terms. As for wanting immutability, it's almost always better for C++ code to write functions not like f but instead like this:
void g(const vector<int>& args);
And apologies for the editorializing, but I do consider this a language design flaw, one inherited from the backwards compatibility for C, which already allowed struct's to be passed (non-pointer) as args and then copied to keep the caller untouchable. It makes C++ code more verbose and more error prone, and is quite difficult for new programmers to grasp.
The value being passed in java is the value of the pointer, where the original pointer value cannot be changed by the function. This is pass-by-reference. Think of pass-by-reference as a special case of pass by value where the value of the pointer to an object is passed rather than the object itself.
If I wanted to write a function that accepted a vector and returned a slightly altered version of that vector I would make a function that does a deep copy and would return that - without ever needing to call the copy constructor myself. I think that it is nice that C++ gives me that option. I don't think that any language is flawless and it's clear that one programmer's feature is, in this case, another programmer's flaw. Keep in mind that this applies to your favorite languages as well.
Edit:
It occurs to me that the distinction is important in multithreaded programs as well. Beyond just worrying about whether or not the underlying data structure is thread safe, passing something by reference might mean sharing memory between two CPUs which can easily lead to a slowdown as the CPUs need to repeatedly flush and resynchronize what's in their cache. Thus unless I have specifically built a thread-safe class whose data has a real need to be shared between between threads I would send data from one thread to another by value rather than by reference.
You just described why I believe pythons 'implicit is always better than explicit' is the most important language design fundamental ever conceived of.
The problem with the C++ approach is that it's default (pass by copy-constructor really) is rather implicit. Your doing a potentially a ton of work with a very innocent function call, with possible side-effects. At least the 'pass a reference by value' behaves the same way EVERY time.
For example, in C++:
myobj a;
somefunction(a);
That copy constructor might trigger a database hit to create a new object if myobj was some sort of ORM. It might call 23 other constructors to fully complete it's deep copy. Who knows, as it all happens rather implicitly. In python, that would look like:
a = myobj()
somefunction(a)
def somefunction(p):
p = copy.deepcopy(p)
In that version I'm now implicitly providing that copy. In your multi-threaded example this is still better, as I get the best of both worlds. Ya, I might lose a bit of convenience... but that explictness is worth the trade-off IMHO.