C# Beginner5 InfinityPassing parameters to functions

Noname from the C# tutorial

You can have a rest

"Infinity was satisfied with your C# level." Ritchie said to me later that day, after I had spoken with Infinity.
"So... does this mean that I'll be chosen for the Rust project?!" I asked.
"You're almost there Teo. You'll also need to pass an exam. If you do, then you are The Chosen One. You'd better go get some rest. The exam will take place tomorrow, and I've already said 'goodbye' to you in my mind, so I want you to pass it."
I nodded and went to the elevator. But instead of going to my floor, I headed to Nonames place in the basement.
When I got there, the atmosphere was... strange. The lights were flickering, Noname was very quiet and instructions on his multiple screens just repeated constantly. What was happening?!
"Hi Noname, how are you?" I asked.
"Hi Teo. I can't find the mistake. There is a mistake, I know, but I can't find it. I-I-I can't find a mistake. I was looking for a mistake but I-I-I c-c-couldn't find it. No mistake, but there is one. Can't find a mistake..." Noname trailed off.
"Okay, okay... I get it. You're looking for a mistake, but you've had no luck in finding it. I'm sorry to see you in this state, how can I help you?" I asked, concerned.
"I have this method, but it doesn't change parameters that I pass to it. I don't understand why. Please, look for an article in the local network, maybe you'll find something useful about passing parameters to methods." Noname begged me.
"Sure Noname, I will do! I'll come back in a little while." I tried to speak optimistically, as I was definitely the only optimist in this room. Come to think of it, I was the only human in the room, and I'm not sure one can apply 'optimistic' to a machine. Still, I knew I had to try to understand what was so tricky about passing parameters to methods...

Back to methods

In next to no time, I had found an article on the local network about passing parameters to methods. I began to read:
"Let's take a simple exercise of calling a method, PrintAndChangeInteger , and passing an int type variable as the parameter."

static void Main()
{
    int exampleInt = 8;
    PrintAndChangeInteger(exampleInt);

    Console.WriteLine($"int after the method call: {exampleInt}");
}

static void PrintAndChangeInteger(int integerToPrint)
{
    integerToPrint++;
    Console.WriteLine($"int inside the method call: {integerToPrint}");
}

// Outputs:
// int inside the method call: 9
// int after the method call: 8

The article continued, "You probably expected the output to be":
int inside the method call: 9
int after the method call: 9

"The trick here, is in how parameters are passed from the Main method to the PrintAndChangeInteger method. In the above example, the parameter exampleInt was copied . The method PrintAndChangeInteger was therefore working with a copy of the exampleInt variable . That's why after the method PrintAndChangeInteger returned, the value of exampleInt remained the same. This type of parameter passing (when the callee copies the caller's parameters) is called passing by value . In this case, if the callee modifies the parameter variable, the effect is not visible to the caller.
As you can imagine, there is another type of parameter passing; passing by reference . When a parameter variable is passed by reference, the caller, and the callee use and change the same variable. If the callee modifies this variable, the effect is visible to the caller."

C# tutorial: pass by value or pass by reference

"Built-in types (except string and object ) by default, are passed by value . This means that almost all types that you know, like int , double , char , etc, are passed in this way. If you, as a programmer, want to pass a built-in type by reference, you should use the keywords ref or out . You should put them before the variable name when you call a method and in the method's parameters list. Here is an example":

static void Main()
{
    int exampleInt = 8;
    
    //---Place-ref-here----↓
    PrintAndChangeInteger(ref exampleInt);

    Console.WriteLine($"int after the method call: {exampleInt}");
}

//----------Place-ref-here---------↓
static void PrintAndChangeInteger(ref int integerToPrint)
{
    integerToPrint++;
    Console.WriteLine($"int inside the method call: {integerToPrint}");
}

// Outputs:
// int inside the method call: 9
// int after the method call: 9

"As you can see in the example, when we passed the parameters by reference, the PrintAndChangeInteger method was working with the same variable as the Main method. That's why the value of exampleInt changed and the output changed too":
int inside the method call: 9
int after the method call: 9

One more C# joke

"But, 'what about out ?' you may ask. The out keyword is very similar to ref . There are two main differences":

  1. The variable should be initialized before passing it as a parameter when using ref . When using out , initialization is not mandatory.
    static void Main()
    {
        int exampleInt; // Not initialized (no value assigned)
    
        ChangeIntegerWithRef(ref exampleInt); // Wrong - exampleInt is not initialized
        ChangeIntegerWithOut(out exampleInt); // Ok
    }
    
    static void ChangeIntegerWithOut(out int integerToChange)
    {
        integerToChange = 2;
    }
    
    static void ChangeIntegerWithRef(ref int integerToChange)
    {
        integerToChange = 2;
    }
  2. The method that takes an out parameter, is required to have a value assigned to this parameter. When the method takes a ref parameter, it can leave its value unassigned.
    static void Main()
    {
        int exampleInt = 2;
    
        PrintIntegerWithRef(ref exampleInt);
        PrintIntegerWithOut(out exampleInt); // This is ok
    }
    
    // This method is ok
    static void PrintIntegerWithRef(ref int integerToPrint)
    {
        Console.WriteLine(integerToPrint);
    }
    
    // Wrong!!! When using out - assign a value to integerToPrint
    static void PrintIntegerWithOut(out int integerToPrint)
    {
        Console.WriteLine(integerToPrint);
    }
    
    // This method is ok. It changes the value of integerToPrint
    static void PrintIntegerWithOutCompiles(out int integerToPrint)
    {
        integerToPrint = 23;
        Console.WriteLine(integerToPrint);
    }

The article continued, "And finally, out in the wild, when you are going to write real programs that are important, please, remember these simple rules":

  1. Avoid using ref and out where possible. Use function return values instead.
    static void Main()
    {
        int input;
    
        // out/ref usage to get a result from the method
        GetNumberFromUserWithOut(out input);
    
        // Return value usage to get a result from the method
        input = GetNumberFromUserWithReturnValue();
    }
    
    static void GetNumberFromUserWithOut(out int input)
    {
        input = int.Parse(Console.ReadLine());
    }
    
    static int GetNumberFromUserWithReturnValue()
    {
        return int.Parse(Console.ReadLine());
    }
  2. Use ref if you want to use the value of the variable inside the method and may need to change it.
  3. Use out if you want to return additional values from the function. A good example is int .TryParse

"All types that are passed by value, by default, are called Value Types . Types that are passed by reference by default, are called Reference Types . You can also remember the difference, by remembering that value types hold the value inside itself, but reference types hold only the reference to a value. Among the types you have learned, string and array are reference types. The rest are value types.
Look at this comparison diagram for int and string variables":

Value types and reference types

The article finished with an example. "Here's an example, where we pass an array to the method, and as an array is a reference type, it is not copied; the method works with the same array as the caller and changes it":

static void Main()
{
    int[] exampleArray = { 1, 2, 3 };
    PrintAndChangeArray(exampleArray);

    Console.WriteLine($"Array after the method call:");
    for (int i = 0; i < exampleArray.Length; i++)
    {
        Console.Write($"{exampleArray[i]} ");
    }
}

static void PrintAndChangeArray(int[] arrayToPrint)
{
    Console.WriteLine($"Array inside the method call:");

    arrayToPrint[0] = 12;
    for (int i = 0; i < arrayToPrint.Length; i++)
    {
        Console.Write($"{arrayToPrint[i]} ");
    }
    Console.WriteLine();
}
// Outputs:
// Array inside the method call:
// 12 2 3
// Array after the method call:
// 12 2 3

I really liked the article. It was clear and easy to understand. After reading everything, I ran to the basement to fix Noname's module. What I found there wasn't the easiest task in the world... but I knew I'd fix it!

C# lesson done

At Codeasy we believe that learning should be fun and engaging. Please reach out to us to share your feedback and collaboration ideas.