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
Pass By Value

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
Pass By Reference

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
Using out Keyword

In

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
Using in Keyword

The 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)
// {
//     
// }
Overloading Method

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!