When providing a parameter to a method, we can either pass a value to it or the variable's reference. Depending upon the method used, the passed parameter can have different values when the method ends. Understanding the difference between the two helps us know exactly what a method is doing to pass data and predict what to expect at the end of the method.
Generally, when a parameter is passed without ref
, out
, in
keyword, the parameter is passed as value.
Pass By Value
When a class or variable is created, data is created in memory along with a reference that points to the created data. Passing by value means that the data is passed to the method.
public class InfoUpdater: MonoBehaviour {
InfoUpdater() {
UserInfo user1 = new UserInfo();
ChangeName(user1);
Console.WriteLine("name " + user1.name + " address " + user1.address);
}
void ChangeName(UserInfo userInfo) {
userInfo.name = "changedName";
userInfo.address = "changedAddress";
userInfo = new UserInfo() {
name = "user2",
address = "address2"
};
}
}
public class UserInfo {
public string name;
public string address;
}
// Output
//
// name changedName address changedAddress
Here, we can see any change made by the method to the parameter directly changes the passed object. Also, notice that after assigning userInfo
to a new class in the ChangeName
method, the passed value user1
from InfoUpdater
still retains its old value. This is because the pass by value doesn't change the reference of the passed parameter.
Pass By Reference
To pass the reference of a variable, the ref
keyword can be used before the passed variable. Method signature should also contain the ref
keyword before the parameter to take it as a reference. When it is used, the object's reference is passed instead of the value. Any assignment or change of reference inside the method is reflected in the passed parameter.
public class InfoUpdater: MonoBehaviour {
InfoUpdater() {
UserInfo user1 = new UserInfo();
ChangeName(ref user1);
Console.WriteLine("name " + user1.name + " address " + user1.address);
}
void ChangeName(ref UserInfo userInfo) {
userInfo.name = "changedName";
userInfo.address = "changedAddress";
// this changes the object referenced by passed parameter
userInfo = new UserInfo() {
name = "user2",
address = "address2"
};
}
}
public class UserInfo {
public string name;
public string address;
}
// Output
//
// name user2 address address2
In this snippet, notice that assigning a new class to userInfo
inside the ChangeName
method also changes the object referenced by the passed reference – user1
in InfoUpdater
constructor. So, the object referenced by user1
is changed at the end of the method.
Other Ways of Passing By Reference
Reference can be passed to a method using in
and out
keyword instead of ref
. These two methods add some restrictions on how references can be modified.
Out
The out
keyword makes sure the passed reference is assigned inside it before exiting the method as the reference passed should always be modified. The parameter passed is usually uninitialized or null as it will be assigned inside the method. It can be used to get multiple results from a single method. Multiple out
parameters can be passed to a method. They will get assigned inside the method, thus resulting in those parameters when the method exits.
public class InfoUpdater: MonoBehaviour {
InfoUpdater() {
UserInfo user1;
ChangeName(out user1);
Console.WriteLine("name " + user1.name + " address " + user1.address);
}
void ChangeName(out UserInfo userInfo) {
userInfo = new UserInfo() {
name = "user2",
address = "address2"
};
}
// this method gives compile error as passed userInfo is not assigned inside it
void DoNothing(out UserInfo userInfo) {
return;
}
}
public class UserInfo {
public string name;
public string address;
}
// Output
//
// name user2 address address2
out
KeywordIn
The in
keyword makes the passed parameter unassignable. The reference of the passed object can never be modified, but if an object is passed, the object's property can be modified.
public class InfoUpdater: MonoBehaviour {
InfoUpdater() {
UserInfo user1 = new UserInfo() {
name = "user1",
address = "address1"
};
ChangeName(user1);
Console.WriteLine("name " + user1.name + " address " + user1.address);
}
void ChangeName( in UserInfo userInfo) {
string s = userInfo.address;
// changing value inside object is allowed
userInfo.address = "changed address";
userInfo.name = "changed name";
// changing referenced object is not allowed if "in" is used
// line below throws an exception if uncommented
// userInfo = new UserInfo()
// {
// name = "user2",
// address = "address2"
// };
}
}
public class UserInfo {
public string name;
public string address;
}
// Output
//
// name changed name address changed address
in
KeywordThe main difference between ref
,in
, out
is that parameters passed with ref
can be modified, parameters passed with in
cannot be modified, and parameters passed with out
must be modified.
While using these, keep in mind that all three keywords seem to have the same signature. It means the method cannot be overloaded by swapping these keywords with each other. However, a method without reference type (pass by value) is seen as having a different signature, so they can be overloaded.
void ChangeName(UserInfo userInfo) {
}
// this is allowed as pass by value and reference are seen as different signature
void ChangeName(ref UserInfo userInfo) {
}
// uncommenting any of following method throws error
// this is because they are seen as having same signature as method with "ref" declared above
// void ChangeName(out UserInfo userInfo)
// {
// userInfo = new UserInfo();
// }
// void ChangeName(in UserInfo userInfo)
// {
//
// }
Understanding parameter types in methods help us track and understand how the method uses the passed parameter. This also helps us restrict passed parameters to ensure that the method uses parameters in an intended way.
Thanks for reading!