The basic idea of a function was to give it information and have it return a single value as a result. That result could have been an integer or a float or even an object or struct. On that principle alone many great programs have been made. However, there came a need for returning multiple values from a function. Sometimes the function not only needed to return a single value but also modify some of the parameters that were passed in. This can be done using two special keywords in C# called “ref” and “out”. They are almost identical but have a subtle difference we will talk about on this short entry of the Programmers Underground!
The subtle difference between “ref” and “out” is that with out the values passed to the function doesn’t need to be given a value first. This means that any function which accepts an out parameter must also plan that the parameter may not have a value. This means that if you pass a value as an out parameter to a function, you can’t assume that it will have a value and thus use it in a math calculation before giving it a value.
Below I have created an example which uses an “out” parameter along with two normal parameters. Where this function would normally return one result, it essentially will return 2. One is the result from dividing the numbers passed in (in this case 5 and 3) and also stores the result of a modulus operation in the out parameter. So after this function is called, both “result” and “remains” variables will have values back in main.
static void Main(string[] args) { int number1 = 5; int number2 = 3; int result; int remains; // Note that remains has not been assigned a value yet result = modDivide(number1, number2, out remains); // Prints "Result is 1 and remainder is 2" Console.WriteLine("Result is {0} and remainder is {1}", result, remains); } static int modDivide(int num1, int num2, out int remainder) { // We can't use remainder itself, it has not been assigned a value. // We can assign to it however. remainder = num1 % num2; return num1 / num2; }
Notice in the code above that we do not actually assign a value to remains prior to passing it to the function “modDivide”. Thus we can’t actually use the parameter “remainder” in any calculations. But we can assign a value to it which will then be available back in caller function (in this case main).
Now ref on the other hand says that the caller (the function calling our function and giving it parameters) must give it a value prior to calling the function. This means that if a function (the callee) accepts a ref parameter it is safe to assume that it will have a value and can be used as such.
If you take our same code and change where it reads “out” and make it “ref” and try to recompile you will get an error that reads “Use of unassigned local variable ‘remains'”. This is because ref doesn’t let us get away with not assigning a value to remains before passing it to the function.
To fix this we have to give “remains” a value before we can pass it to the function. This allows our function modDivide to depend on the parameter “remainder” as having some sort of value. Of course we still have to make sure it is the right kind of value and in the range of expected input.
static void Main(string[] args) { int number1 = 5; int number2 = 3; int result; // Notice that we gave remains a value. int remains = 0; // Now remains has a value, we can pass it as a ref parameter. result = modDivide(number1, number2, ref remains); // Prints "Result is 1 and remainder is 2" Console.WriteLine("Result is {0} and remainder is {1}", result, remains); } static int modDivide(int num1, int num2, ref int remainder) { // We can now use remainder because it actually has a value. // But in our example we are still going to use it to store our modulus result. remainder = num1 % num2; return num1 / num2; }
Now I find more use for ref than I do for out. Often times it is more efficient to pass in an object using ref and modify it than using out and having to check if it has a value and then assigning a value to out. Once in a great while you may find the need to use out, but use it sparingly.
If you find yourself having too many ref and out parameters (more than 2 usually) then that is a red flag that you could refactor your code down and make things much simpler. As with all good things you don’t want to abuse it too much or it will work against you. Moderation is the key here.
I hope you found this small lesson a useful one for you and now you know the subtle difference between the two keywords. Thanks for reading and to those in Canada, Happy Canada Day! 🙂