- Home /
Passing Parameters by Value or by Reference
Passing something to a function that changes a variable/object outside the function, vs passing things to the function that are lost upon completion of function.
I know classes have this ability, while basic variable types are instanced in the function.
For example
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;// <---- modifying this variable
if (Physics.Raycast(ray, out hit, 100))// <- by putting it in this function
Debug.DrawLine(ray.origin, hit.point);
DoStuff(hit.thingsSetDuringFunction);
Answer by Bunny83 · Dec 30, 2016 at 01:13 AM
Well, a lot people seem to confuse the concept of value / reference types with the concept of passing parameters to methods. It's a general misconception that reference types are passed by reference. By default all parameters are passed by value.
Let's start by defining what a parameter is. A parameter is just a local variable that only exists within the scope of the method. Those variables are "initialized" when you call a method by the values that are passed in.
The biggest confusion seems to come from passing a reference type variable by value. What is the "value" of a reference type variable? It's simply the reference to an object. Of course a method can use a reference that was copied (passed by value) into the local parameter variable to directly access / modify the object behind the reference, but the variable that was passed in can not be modified.
So there are basically two variable type families (value types and reference types). And there's also two different ways to pass a variable to a method (passed by value and passed by reference). Note that this only applies when passing variables to a method. Literal values are always passed by value.
the default: pass by value
Consider the following methods:
void f(int x) { }
int g(GameObject obj) { return 5; }
By calling f(5);
we actually copy the integer value of 5 into the local variable "x" of the method "f". The same concept holds true for reference types.
If we call g( new GameObject("test") );
we create a new gameobject and copy the reference to that object into the local variable "obj". In both cases we have copied the value that was passed to the method into it's local parameter variable.
Passing variables to such methods has the same effect.
public GameObject myObj;
public int myInt = 7;
By calling f(myInt);
we copy the value of the variable "myInt" into the variable "x" and if we call g(myObj);
we copy the reference which is stored in the variable myObj into the variable "obj". The method can not modify the passed variable. It can use and re-assign it's local variable but it won't affect the content of the variable that was "passed in". Keep in mind that the "content" of reference type variables is the reference, not the object behind the reference.
pass by reference (out, ref)
It's possible to declare a parameter of a method as reference parameter by using the "ref" or "out" keyword. They both serve the same purpose but "out" has some additional properties which i will explain below.
Consider those methods:
void h(ref int y)
{
Debug.Log("current value of y: " + y);
y = 42;
}
void k(ref GameObject obj)
{
obj = new GameObject("test");
}
When you call those methods you have to use the "ref" keyword and you have to use an actual variable. It's not possible to pass in a value, only variables. The "ref" is about the variable and not it's content. So when calling h(ref myInt);
you don't copy the content of myInt into the local variable. Instead the local variable becomes an alias for the passed in variable. So you basically pass a pointer to the memory location where the passed variable is stored. So when using that alias you actually using the original variable. That means you can read and write the content of the original variable. After calling "h" with myInt as ref-parameter myInt will contain "42".
The same happens when you call k(myObj);
. The method actually replaces the content of myObj with a newly created GameObject. Again, keep in mind that the content of a reference type variable is "the reference".
The "out" keyword
Like i said above out
does the same as ref
but has some additional constraints for both, the caller and the method:
A method with an out parameter has to ensure to initialize the variable with some value.
The method can not read the out parameter before it has got assigned inside the method. It's treated as uninitialized variable.
The caller can rely on the above fact that a method has to assign a value to the passed variable. Therefore passing an uninitialized variable to an out-parameter is considered an initialization of the variable.
So out parameters are just a special version of a ref parameter. It's generally used when you just need to return something but don't need to pass in a "current" value. A common example in Unity is the RaycastHit parameter of the Physics.Raycast method. Another general example is the TryParse method of most primitive datatypes.
Additional restrictions for ref-parameters
ref-parameters are like a special kind of variable type that doesn't exist as normal variable type. So it's not possible to "store" or return such a variable reference. ref-parameters can be passed further down to other methods with ref parameters but never "upwards" as this would allow to return a reference to a local variable of a method that is out of scope and extent.
ref-parameters can not be used for coroutines. Coroutines are implemented with auto generated statemachines. Statemachines have to store the current state in class variables. Since ref-parameters can't be stored in class variables they aren't supported for coroutines. This is not a limitation of Unity but a limitation of the ref-parameter itself. Trying to declare a parameter of a coroutine as ref or out parameter will cause a compile error.
Finally i want to note that ref and out parameters aren't something Unity specific. They are features of C# / .Net and all those limitations come with them and aren't Unity specific. If you need further information on that topic or if you have trouble understanding what i just said, you might want to refer to some general C# / .NET resource like StackOverflow.
A very thorough answer. I'd only add that out
parameters are useful when you want to return multiple values from a function.... otherwise you simply return
a single result.
I am writing because i want to be sure about a thing that you said:
"The method can not modify the passed variable. It can use and re-assign it's local variable but it won't affect the content of the variable that was "passed in". Keep in $$anonymous$$d that the "content" of reference type variables is the reference, not the object behind the reference."
Please correct me if i am wrong.What you tried to say is content" of reference type variables are not directly affected but local variable has the same adress with the copy of the reference type and we know that if we change something via that local variable ,we also change all the variables(includes copy too) that contain that memory adress as well, so content of the variables are indirectly affected by that method's local variable
Answer by tanoshimi · Dec 29, 2016 at 11:46 AM
It sounds like you're talking about:
passing parameters by value (i.e. when a function receives and modifies a copy of a variable, which is the default for structs and simple types like int, float etc.)
vs
passing parameters by reference (when a function receives a reference to the variable itself and modifies the original, which is the default for classes).
If that is the extent of the formal ter$$anonymous$$ology then I'll mark the question answered, but i would thoroughly appreciate any tangential info, or sources/example for exact use, and variation of use (i.e. how can i pass a simple type by reference, or entire classes "by value" if i want something to manipulate but to keep the original)