What is the difference between "passing by value" and "passing by reference"?

Asked

Viewed 23,304 times

39

I know that in the first the object passed as an argument to a function is copied, and in the second not. I also know that it is extremely unusual in modern languages to pass complex objects by value, while primitive types (numbers, characters, boolean...) often are. But what exactly are these modes of passage? I read a lot that "in Java references are passed by value", and I also see that there are modern languages (such as C#) that give more options to pass parameters than most Object-Oriented languages.

What I’d like explained is:

  • "In the passage by value the argument is copied." OK, but what exactly is copied? The entire object, including all its references?

  • What constitutes a reference passage? If the language has pointers, passing a pointer to an object as argument means passing the object by reference?

  • What exactly does it mean to "pass a reference by value"? (back here the first item - what reference is being copied, since the passage is by value?)

In order not to get too wide (if not already), I ask that the answers focus on the C/C++ languages (traditional, which introduced to many of us the concepts involved), Java (which for me at least marked the paradigm shift between reasoning in terms of pointers and in terms of references) and perhaps C# (modern language that if I’m not mistaken brought more flexibility in the ways of manipulating objects).

  • 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.

  • 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 pointer ptr by value and the value to which it points by reference. Already funcao(int **ptr) passes the pointer itself by reference.

  • 1

    Dangerous response, since many can be done differently from one language to another.

3 answers

31


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).

9

"In the passage by value the argument is copied." OK, but what exactly is copied? The whole object, including all its references?

What is copied is exactly the value that was passed as argument. This value can be a primitive, can be an object, can be a pointer (a memory address) or can be a reference to an object (such as the value of a variable that points to an object, like any variable that contains an object in Java). If an object is passed and this object has references to others, it is not made a deep copy of the object, but a copy of the references it contains (at least in the languages I know, and whereas the language allows the direct passage of an object, by value).

What constitutes a reference passage? If the language has pointers, passing a pointer to an object as argument means passing the object by reference?

Strictly speaking, passing a pointer does not constitute passing by reference. Keep in mind that reference is something more abstract than pointer, is a concept, and can be either used to explain a functionality (in languages that formally implement a "pass by reference"), or a behavior (in languages that do not implement it but allow it to do so in other ways).

In C, for example, there is no "reference passage". If you pass a pointer, what is passed is a copy of the memory address where the object is, and that address is stored in a new pointer with local scope in the function. Depending on what you do with this pointer, you may or may not get the same behavior as a reference passage:

  • If you change the value of the pointer (the address it stores), the original object is unaffected, unlike a passage by reference.

  • If you uncheck the pointer and change the value stored in the address it records, the behavior is equivalent to a reference passage.

What exactly does "passing a reference by value" mean? (return here the first item - what of the reference is being copied, since the passage is by value?)

Passing a reference by value is quite different from passing a value by reference! To explain this, think of any variable that contains an object. For example, in Java:

Foo bar = new Foo();

The variable bar contains a reference to an instance of Foo. This instance has its own identity, whose representation is even exposed by language if you ask for a bar.hashCode(). There may be multiple references to that same object:

Foo baz = bar; // cria uma CÓPIA da referência, apontando pra o mesmo objeto

When passing this object to a function, the same occurs as in the above assignment: a copy of the reference is created. The reference has a value, and this value represents a way to find the object in memory (probably involving pointers, but this is implementation detail - in the case of Java, the JVM implementation). It is this value that is copied when a reference is passed by value. Changing this value does not change other references with equal value. You can manipulate the object to which the reference points, but if you assign something directly to the reference, the object is not affected.

Already a passage by reference directly manipulates what is referenced. If an object is passed by reference and the variable representing that reference is nullified, the object ceases to exist.

-1

In summary, passing by value does not change the result of the variable (before the passage is made) and is thus less economical in terms of memory expense.

Already the passage by reference , the program will directly change the value of a specific memory address.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.