Objectives
By the end of this lesson you will be able to:
- Understand what a function is
- Understand what a method is
- Create a custom function
- Create a custom method
- Understand what arguments are
- Understand what parameters are
- Call a custom function and pass it an argument
- Call a custom method and pass it an argument
- Understand variable scope
- Contrast passing by value to passing by reference
Introduction
Procedural programming introduced the concept of the goto
and gsub
commands into programming languages. The idea of goto
was to redirect program flow from its current line position to the line number identified in the goto
statement, i.e. goto 400
. Gosub
would also redirect program flow from the current line to the line specified in the gosub
statement, however, that line number was the beginning of a structure known as a subroutine (a predecessor to today's methods and functions; when the subroutine ended, flow control would return to the line immediately after the line that contained the gosub
statement.
This style of coding caused what was known as "spaghetti code" because it was difficult to trace the program flow and even more difficult to recall the significance of a particular line number or subroutine's intent when the pointer was simply a numeric value.
Most all modern programming languages include the concept of a function or a method, in Assembly language they call this structure a procedure; in general they are almost synonymous but there are some distinctive differences depending on the programming language used.
⇑ Table of Contents
Video Lecture
Understanding Functions & Methods
Functions and methods are code blocks containing a series of statements. Functions and methods can receive input via arguments sent by a caller and can return a value to the caller.
Essentially, functions are no different than methods, they both operate the same way. They both consists of blocks of code which provide some sort of functionality in a program and then return program control back to the caller of the function or method. Generally speaking the only difference between the two is where they are used. In some languages these code blocks will be called a function, like JavaScript, and in other languages they will be called a method, like in C#. Also, you will generally find functions used in procedural languages and methods in object-oriented languages.
In the Hello World program we wrote earlier you learned about the Main method. Methods are where the action is in a program. More precisely, a method is a set of statements that are executed when the method is called by another line of code somewhere else in the program.
The Main method doesn't return a value back to the calling code. This is indicated by the void keyword in it's signature (the first line of the method). If a method were to return a value, the appropriate data type for the return value would be used in the place of void in the method's signature.
Class members like methods, can have access modifiers such as static, public, and private in their signature. These modifiers specify how and where class members can be accessed.
Visual Studio Solution: source code examples for Tutorial 10.
⇑ Table of Contents
Examples of Creating and Using Functions
Watch this video to learn how to create and use functions in your computer programs.
⇑ Table of Contents
Creating and Using Custom Methods
Up to this point, all of the programs that you have written have been written inside of the Main() method of the Program class. Essentially what this means is that each time you run your program a copy of the Program.cs file is loaded into the computer's RAM and the first statement inside the Main() method is sent to the Common Language Runtime (CLR) for processing. Once all the lines of code in the Main() method have been processed, the program ends.
What if you wanted to run the same bit of code several times before your program ended? Would you copy all of the statements inside the Main() method and paste them back into Main() however many number of times you wanted the same process repeated? Hopefully, your impulse is to say NO - yes in all-caps - because this would violate one of the cardinal rules of programming - don't repeat yourself (DRY). The following exercise will help demonstrate how methods can solve this dilemma.
⇑ Table of Contents
Example of Creating and Using A Custom Method
Create a new Visual Studio C# Console Solution named "Methods", name the first project "Method1" and paste the following code into the Main() method of the Program class:
int number1 = 10;
int number2 = 20;
if (number2 > number1)
{
Console.WriteLine("number2 is greater than number1");
}
else
{
Console.WriteLine("number1 is greater than number2");
}
Examine the code and notice it is very similar to the if/else code you used in the Decisions Structures tutorial. Two integer variables, number1 and number2, are initialized with the values 10 and 20 respectively. Then, using an if-else coding structure, the program evaluates the conditional expression which compares the value of the number2 variable to the value of the number1 variable to determine if number2's value is greater than the value stored in the number1 variable. If the conditional expression evaluates to true, the Console's WriteLine() method is used output to the display the phrase "number2 is greater than number1". If the conditional expressions evaluates to false, the Console's WriteLine() method is used output to the display the phrase "number1 is greater than number2".
Press Ctrl+F5 on your keyboard to run the program and see the results. Change the values of number1 and or number2 to confirm that the decision structure is evaluating the expression as expected.
Now that we know our code is running as expected, we need to ask ourselves how we can compartmentalize this code so that it can easily be re-used without having to re-type it over and over again. Let's create a custom method in our program call it every time we want our code to run. Methods, like functions, have a signature and a body. A C# method's signature defines its: its accessibility, whether or not it can be used statically, the data type it returns if any, its name, and the name and type of any parameters it accepts from callers.
In our case we won't worry about accessibility by other programs (the default is public), but we do want to indicate that we can use it statically within our program, that it will not return any values, we'll call it compareNumbers, and initially we don't want it to accept any parameters. Here is a dissection of what all this means and looks like in code.
Start underneath the Main() method (after its closing curly brace) and type the following:
static void compareNumbers()
{
// add statements here
}
Next, cut the code inside the Main() method and paste it inside of the compareNumbers() method. Your code should like this:
At this point our method has been defined and is ready to be used. As we have learned, in a C# Console application the only code that runs after the program is loaded into RAM needs to be inside of the Main() method. The runtime knows our custom method exists, but does not run it unless it is called. To do this (call it) simply type the name of the method inside of the Main() method as a statement (include the parenthesis with the name of the custom method and end the statement with semi-colon). It is important to remember that C# is a case-sensitive language, meaning when you want to call a any method be sure you type its name exactly as it is typed in the method's signature.
After adding the "call" to the compareNumbers() custom method, go ahead and run the program by pressing Ctrl+F5 on your keyboard.
Now you can run that bit of code over and over again by adding several calls to it inside of Main(), or by adding the one calling statement inside of a loop that runs several times. However, the limitation we see is that it always prints the same output because the variable's values are hard-coded into the method. As you will see in our next example, we can solve this issue by making a slight change to the method's signature. We will configure it to accept parameters.
⇑ Table of Contents
Passing Data With Functions
Watch this video to learn how functions receive parameters and how the callers of a function pass arguments to the function its calling.
⇑ Table of Contents
Passing Data With Methods
In order for our custom method compareNumbers() to receive data sent to it by its caller we need to add parameter information inside the parenthesis of the method's signature. In order to define the parameters our custom method will accept we must identify the data type the passed value must conform to and a name to represent the passed data internally inside the custom method's body.
Since we want to receive two numbers for comparison internally in our custom method we'll add two parameter declarations, each being of int
data type like this:
static void compareNumbers(int number1, int number2)
You will notice that Visual Studio freaks out when you do this because now we have declared the variables number1 and number2 in two places in our code for the compareNumbers method. To resolve this issue delete the two statements inside the compareNumbers method which declare the number1 and number2 variables.
You'll notice that Visual Studio is still not happy showing an error in the Main() method for the caller statement. The Intellisense recognizes that calling the compareNumbers() method without passing it the required data will cause an error. This is an easy fix.
Now that our custom method will accepts two values passed to it in int format, we will modify the call to it in the Main() method of our program and pass it the two required int values as arguments.
like this:
compareNumbers(100,200);
Go ahead and press Ctrl+F5 to run your program. If you run into errors check your code against the code listing below.
using System;
namespace Method1
{
class Program
{
static void Main(string[] args)
{
compareNumbers(100,200);
}
static void compareNumbers(int number1, int number2)
{
if (number2 > number1)
{
Console.WriteLine("number2 is greater than number1");
}
else
{
Console.WriteLine("number1 is greater than number2");
}
}
}
}
Add several more calling statements to compareNumbers changing the two values passed to it on each call.
⇑ Table of Contents
Variable Scope
The ability for your source code to access its declared variables will vary depending on where in your program the variable has been declared; this is known a variable scope. Watch this video to learn how variable scope works and how it impacts its availability within the program.
⇑ Table of Contents
Demonstrating Variable Scope
Local Variable Example
Notice that in this example x is a local variable. Its scope is local to the method where it is declared.
Global Variable Example
Notice in this example x is a global variable. Its scope is the entire program because it was declared outside of any methods.
⇑ Table of Contents
Passing By Value Versus Passing By Reference
In the examples we have seen so far where variables were passed into a functions or methods, the type of variables being passed were always primitive, simple types not custom complex types. All the primitives, except strings, enumeration, tuple, and structures are value types. Classes, strings, interfaces, arrays, and delegates are reference types. Every type has a default value.
Types that you define by using the struct keyword are value types; all the built-in numeric types are structs. Types that you define by using the class keyword are reference types. Reference types and value types have different compile-time rules, and different run-time behavior.
Why this is important is because value types and reference types are passed differently to functions and methods. When a function or method is being called which passes parameters to the function, value types have thier literal value placed on the stack - the value that is stored in memory where the variable is pointing. When a function or method is being called which passes a complex data type (a.k.a. reference type) like and array or an object, it is the memory location of the array or object that is being passsed. If you think about it, to retrieve a value stored in an array or object requires more information than just the name of the array or the object. In the case of an array, an index value would be needed to target a specific value stored in the array. In an object a property or method name would need to be referenced using dot notation; e.g. MyObject.PropertyName.
The ref keyword in C# is used for passing or returning references of values to or from Methods. Basically, it means that any change made to a value that is passed by reference will reflect this change since you are modifying the value at the address and not just the value.
Here are two examples of calling a function which uses reference type parameters, in the first example the parameters are passed by value, which retrieves the memory address. In the second example, the same parameters are passsed, but by reference instead of value.
Passing By Value
When passing a value type variable to a method, a copy of the variable's value is put on the stack. The method then runs and when it completes the value being used in the method is popped (removed) from the stack.
namespace PassingByValue
{
class Program
{
static void Main(string[] args)
{
int x = 10;
Console.WriteLine("Variable Value Before Calling the Method: {0}", x);
Multiplication(x);
Console.WriteLine("Variable Value After Calling the Method: {0}", x);
Console.WriteLine("Press Enter Key to Exit.");
Console.ReadLine();
}
public static void Multiplication(int a)
{
a *= a;
Console.WriteLine("Variable Value Inside the Method: {0}", a);
}
}
}
Passing By Reference
In cases where a reference type variable is being passed to a method, it is the address where the value is stored in memory that is placed on the stack.
namespace PassingByReference
{
class Program
{
static void Main(string[] args)
{
int x = 10;
Console.WriteLine("Variable Value Before Calling the Method: {0}", x);
Multiplication(ref x);
Console.WriteLine("Variable Value After Calling the Method: {0}", x);
Console.WriteLine("Press Enter Key to Exit..");
Console.ReadLine();
}
public static void Multiplication(ref int a)
{
a *= a;
Console.WriteLine("Variable Value Inside the Method: {0}", a);
}
}
}
More Practice With Functions & Methods
C#
Here is how the code in our Program.cs
file will look. In this example you will create two methods, Main() and compareNumbers(). Place the code inside the Program() class and run it.
static void Main(string[] args)
{
compareNumbers(100, 200);
compareNumbers(100, 20);
compareNumbers(1000, 200);
}
static void compareNumbers(int number1, int number2)
{
if (number2 > number1)
{
Console.WriteLine(number2 + " is greater than " + number1);
}
else if (number1 > number2)
{
Console.WriteLine(number1 + " is greater than " + number2);
}
else
{
Console.WriteLine(number1 + " equals " + number2);
}
}
An Improved Version
static void Main(string[] args)
{
Console.WriteLine(compareNumbers(100, 200));
Console.WriteLine(compareNumbers(100, 20));
Console.WriteLine(compareNumbers(1000, 200));
}
static string compareNumbers(int number1, int number2)
{
string output;
if (number2 > number1)
{
output = number2 + " is greater than " + number1;
}
else if (number1 > number2)
{
output = number1 + " is greater than " + number2;
}
else
{
output = number1 + " equals " + number2;
}
return output;
}
If we want the program to take user input, we could change the main() method like this:
Console.WriteLine("Enter two integer values.");
int number1 = Int32.Parse(Console.ReadLine());
int number2 = Int32.Parse(Console.ReadLine());
Console.WriteLine(compareNumbers(number1, number2));
⇑ Table of Contents
Summary
In this lesson you learned what a function is, what a method is, how to create a custom function, how to create a custom method, what arguments are, what parameters are, how to call a custom function and pass it an argument, how to call a custom method and pass it an argument, what variable scope is.