Introducing: GUYS by value/reference versus PASSAGEWAY by value/reference
Much of the programmers' resistance in accepting an explanation about passageway by value/reference comes from the confusion they make with guys by value/reference, but they are completely different things. Then follows a brief introduction about types by value/reference:
Types per value
Speaking at a high level, without getting into the merit of memory management or implementation details of languages/platforms, we can say without fear of making a mistake that an initialized variable always contains a value:
int X = 1;
Integer is a type per value. A type per value variable stores the value itself. In the above code, therefore, the variable X contains the value 1.
Types by reference
Now consider the code below:
String Y = "1";
String is a type by reference. The variable Y, as well as the variable X, also contains a value, but the variable value Y is not "1"! The variable value Y is a reference to a string object.
Another way of saying: the variable Y does not store the value assigned to it but rather a reference to this value, which is somewhere else in memory.
A common analogy* is to say that a variable of a type by reference contains the address of the value or the address of the object representing the value, rather than the value itself. But this address, by itself, is also a value (in some respects).
*Analogy** because in many languages, such as Java and C#, the reference cannot be manipulated as an address or a truth pointer could be.
Since there is support in the language, an object by reference can be passed both by value and by reference; and an object by value can also be passed both by value and by reference.
The rest of the answer will demonstrate this and will also demonstrate that:
The object type (either by value or by reference) does not affect the way it will be passed by parameter (whether by value or by reference), but may affect the effects that interaction with this parameter can cause on the object.
To try to avoid confusion, the rest of the answer calls the types by value of "primitive types", and the types by reference of "complex types", which is how they are known in some communities.
Difference between passing by value and passing by reference
The simplest, most high-level definition I can think of is:
In passing through value, a copy of the variable’s value is passed.
In passing through reference, a reference to the variable itself is passed.
This is true regardless of the type of the variable.
That is to say, no matter if the type of a variable is primitive or complex, the above statement is always true.
See this code (valid in both C# and Java) where we pass an argument per value:
void metodoQualquer(int parametro1) {
parametro1 = 26;
}
...
int meuNumeroFavorito = 13;
metodoQualquer(meuNumeroFavorito);
//aqui, *meuNumeroFavorito* permanece 13.
In the code above, method received a copy of the value of meNumerFavorite, then when he changed this value, he was changing a copy and did not affect the value of the variable meNumerFavorite.
Now see this code (valid in C# but not in Java) where we pass an argument by reference:
void metodoQualquer(ref int parametro1) {
parametro1 = 26;
}
...
int meuNumeroFavorito = 13;
metodoQualquer(ref meuNumeroFavorito);
//aqui, *meuNumeroFavorito* agora é 26!
In the code above, method received a reference to the variable meNumerFavorite, then it changed the value of the variable itself instead of changing a copy of its value.
This code is valid in C# but not in Java because Java does not support reference passthrough.
Passing complex types by value
The behavior observed when we pass complex types by value confuses some people.
Let’s see a complex object being passed by value:
void metodoQualquer(Objeto parametro1) {
parametro1.atributo = 26;
}
...
Objeto meuNumeroFavorito = new Objeto();
meuNumeroFavorito.atributo = 13;
metodoQualquer(meuNumeroFavorito);
//aqui, *meuNumeroFavorito.atributo* agora é 26.
So I passed an argument by value and the changes made in this argument are perceived in the original variable.
This is because a complex type variable contains a reference to the object. The word "reference" here has another meaning. We can say that reference, in this context, is the memory address where the object actually resides. So the variable actually contains a memory address, and if we go to this address we’ll find our object there.
When I pass this variable as an argument to the method, since the argument was passed by value, a copy of the variable content has been made - this content is the reference to the object, that is, its address. And now each variable contains a copy of the address of the same object. So that by changing the attributes of this object through one of these variables, the effect will be perceived by accessing the object by the other variable.
meuNumeroFavorito -> contém o endereço #B5F67
parametro1 -> contém o endereço #B5F67
No endereco de memória #B5F67, reside o objeto para o qual ambas as variáveis apontam.
And the struct?
In C# we have structs, that as well as int is also a type per value, which is what I’ve been generalizing in this answer as primitive type.
In C#, "primitive" and "complex" type can become too simplistic nomenclature, since all types inherit from Object and I can declare types in the same way that such primitives are declared, using struct.
A variable of the type of a struct does not contain a reference (or address) to an object but does contain its actual value, so when we pass a struct by value, the struct is copied.
See code C# below:
struct MeuInteiro
{
public int atributo;
}
...
void MetodoQualquer(MeuInteiro meuInteiro)
{
meuInteiro.atributo = 26;
}
...
var meuInteiro = new MeuInteiro();
meuInteiro.atributo = 13;
MetodoQualquer(meuInteiro);
// aqui, *meuInteiro.atributo* permanece 13!
The value of the struct attribute passed by value was modified within the method and this modification was not perceived outside the method. That’s because it was made, shall we say, a complete copy of struct when passing it by value. References that struct has to other complex objects are copied as well.
If in the above code I just change the statement struct Meuinteiro for class Meuinteiro, the result will be different - after the execution of Method the value of menInteiro.attribute will have been modified to 26.
Passing complex types by reference
When passing a complex type by reference, I do not pass the object address but rather a reference to the variable being passed as argument. And then I can change the address contained in this variable to make it point to another completely different object.
As I said, Java only supports pass by value, so the code below is only valid in C#:
void metodoQualquer(ref Objeto parametro1) {
parametro1 = new Objeto();
}
...
Objeto meuNumeroFavorito = new Objeto();
metodoQualquer(ref meuNumeroFavorito);
//aqui, *meuNumeroFavorito* agora aponta (ou "referencia") outro objeto completamente distinto.
Direct answers to your questions
In the passage by value the argument is copied. OK, but what exactly is copied? The whole object, including all its references?
In Java and C#, if "object" is of a primitive type, in fact it is copied when passed by value. If it is of a complex type, the object itself is not copied - what is copied is the reference to the object (or the "address" of the object).
If an object is passed and that object has references to others, these other references are not copied:
void metodoQualquer(Objeto parametro1) {
parametro1.atributo = null;
parametro1 = null;
}
...
Objeto argumento = new Objeto();
argumento.atributo = new OutroObjeto();
metodoQualquer(argumento);
//aqui, *argumento* manteve sua referênia ("endereço") para a mesma instância de Objeto
//e *argumento.atributo* agora é null.
The above code demonstrates that in passing a complex type by value, the reference to the object is copied but the references it has are not. (Exception to structs of C#, explained in your specific session).
What constitutes a reference passage?
It constitutes a reference to the variable itself that is passing as argument. Do not confuse this "reference" with a reference to an object in memory.
If the language has pointers, passing a pointer to an object as argument means passing the object by reference?
No, the pointer can be passed by either value or reference.
See: you pass a pointer to an object. If you pass this argument by value, the pointer is being copied. If you pass this argument by reference, you are passing a reference to its original variable, and the pointer contained in it can be changed within the method so as to point to another object.
What exactly does "pass a reference by value" mean? What of the reference is being copied, since the passage is by value?
What is being copied is the very reference to the object and only it. We can give another name to this reference that is being copied - we can call it "address". Thus, what is being copied is the address of the object and not the object itself.
Completion
In passing by value, a copy of the variable’s value is passed.
In the reference passage, a reference is passed to the variable itself.
The type of the variable (whether "primitive" or "complex") has no relation to the fact that it will be passed by value or by reference.
When a method manipulates a primitive type variable passed by value, this manipulation is not perceived outside the method.
When a method manipulates the attributes of a complex type variable passed by value, this manipulation is perceived outside the method.
Java supports pass-by-value only.
C# supports passing by value and by reference.
In Java and C#, no copy of the complex type object is made when passing it by value. What is copied is the reference to the object (or the "address" of the object).
I missed a question in Sopt explaining these two concepts. A equivalent question in Soen has some good answers, which can serve as inspiration for those who answer.
– mgibsonbr
It depends on what you mean by value, the value to which the pointer points or the pointer value itself.
funcao(int *ptr)
pass the pointerptr
by value and the value to which it points by reference. Alreadyfuncao(int **ptr)
passes the pointer itself by reference.– Rafael Bluhm
Dangerous response, since many can be done differently from one language to another.
– pmargreff