As you saw above, all programs must define a subroutine called Main, which is the starting point for the program. But you can also add other subroutines. Usually you would create a subroutine when you want to perform the same set of instructions, perhaps with slight differences, several times in a program.
The SayHelloWorld Subroutine
Let’s have a look at how you would create a subroutine. In the source window, right after the End Sub of the Main subroutine, add a newline and then add the following italic code below:
Module Module1
Sub Main()
Console.WriteLine("Hello, world!")
End Sub
Sub SayHelloWorld()
Console.WriteLine("Hello, world!")
End Sub
End Module
You can see that the SayHelloWorld subroutine has some similarities with the Main subroutine. In fact, apart from their names, the Main subroutine and the SayHelloWorld subroutine are identical – they both call Console.WriteLine. Let’s see how the SayHelloWorld subroutine works in action. Modify the Main subroutine so that it calls the SayHelloWorld subroutine instead of calling Console.WriteLine, as follows:
In the Main subroutine, delete the line that reads
Console.WriteLine("Hello, world!")
Add a line that reads
Now run the program without debugging (Ctrl-F5). There’s no visible change between the output of the original program and the new version. The only difference is that the Main subroutine no longer writes to the console itself; it calls a different subroutine to write to the console on its behalf.
The SayHelloTo Subroutine
The SayHelloWorld subroutine doesn’t add much to your program – it’s just a way of illustrating how you can create and call a subroutine. Now let’s create a different subroutine, a bit more useful this time because it’s slightly more flexible.
Add the following italic code below, right after the SayHelloWorld subroutine:
Module Module1
Sub Main()
SayHelloWorld()
End Sub
Sub SayHelloWorld()
Console.WriteLine("Hello, world!")
End Sub
Sub SayHelloTo(ByVal toWhom As String)
Dim message As String
message = "Hello, " & toWhom
Console.WriteLine(message)
End Sub
End Module
You can see the obvious similarities between this subroutine and the SayHelloWorld subroutine. But there are some interesting differences, too. Before we examine them, let’s see this subroutine in action. Modify the Main subroutine by adding the following lines right after the line that calls SayHelloWorld:
SayHelloTo("Eric")
SayHelloTo("Sandra")
Run the program without debugging. You should see the following output:
You can probably see the gist of what’s going on here. The SayHelloTo subroutine allows you to specify to whom to say hello, by putting the name of the person as a parameter when you call the subroutine (you can think of a parameter as an input to a subroutine). We put parenthesis “(” and “)” around the parameters after the subroutine name.
Within the SayHelloTo subroutine, we don’t know what the actual value of the parameter will be when someone calls the subroutine. In this program, the values “Eric” and “Sandra” are used; but you could use other values instead. The SayHelloTo subroutine needs a way of handling the value without knowing what the value actually is. To get round this, Visual Basic enables us to create a ‘slot’ for the value, and give that slot a name. In this subroutine, we’ve called the slot toWhom. The proper term for the slot is a variable, so called because the slot’s value can vary. Don’t worry too much about the other details of this subroutine for now – we’ll revisit them further on.
Variables and Data Types
Variables are very important features in Visual Basic, or any other programming language. A variable is where you can store information and retrieve it (in computer terms, a variable refers to an area of computer memory where the variable’s value is stored). You must give the variable a name, which you then use when storing or retrieving information from that variable. The name you use for a variable can be anything that you choose, subject to a few restrictions:
Variable names can only contain letters, numbers, and the underscore ‘_’ character. They cannot contain spaces or punctuation.
Variable names cannot start with a number.
Variable names must not clash with other variable names – you cannot use a variable name if it’s already in use in the same part of the program (this restriction isn’t as severe as it may seem, for reasons that will become apparent).
To help the computer set aside the right amount of memory for the variable, Visual Basic requires that you specify a data type in addition to the variable name. A data type, as the name implies, denotes what type of data the variable will hold. There are many different data types in Visual Basic, and you can create your own; but some examples of the most commonly-used types are:
Data type | Description | Example |
Integer | An integer, 4 bytes in size, which can hold a value between -2,147,483,648 and 2,147,483,647 | 43 |
Byte | An integer, 1 byte in size, which can hold a value between 0 and 255 | 127 |
Decimal | A number with decimal places, which can hold a value between ±1.0×10-28 and ±7.9×1028 | 10966.2592 |
String | A sequence (or “string”) of characters | "Hello, world!" |
Char | A single character | 'h' |
Boolean | A logical value which can be either True or False | True |
Before you can use a variable, Visual Basic insists that you declare it. This means that you must specify the type and the name of the variable, so that the program knows what you are talking about before you start to use it. A declaration can be a simple statement such as
In fact, you can configure Visual Basic so that it doesn’t insist that you specify a data type. However, this feature is really just for backwards compatibility with older programs, and you should never need to set this up.
This declares a variable called x which will contain values of integer type. You can optionally assign a value to the new variable when you declare it, as follows:
This statement declares a variable called y, as above, and then initializes it with a value of 43.
Visual Basic imposes an important restriction on your use of variables. It does not allow you to store a value that has one data type in a variable of a different data type. This can be a little confusing at first, because you can’t do some things that seem perfectly obvious. For example, here is some code that declares two variables and assigns values to those variables.
Dim myInteger As Integer = 43;
Dim myString As String = "43";
It might seem obvious that myInteger and myString have the same value, but to the computer these variables have completely different values. In fact, they have completely different types, so you couldn’t even compare myInteger and myString to see if they were the same value! myInteger can only contain values of type Integer, while myString can only contain values of type String. So even though 43 is an integer value, when we put quotes ("") around it, Visual Basic treats whatever is between the quotes as a String value.
Visual Basic does have one trick up its sleeve, however. If you assign a variable with one data type to a variable with another data type, Visual Basic will try to convert the right-hand value to the correct data type to match the left-hand variable. If successful, the program will continue. The problem is that sometimes the conversion won’t succeed, and when that happens, your program can’t continue.
Let’s have a look what happens when you try to mix data types. Create a new method in the program by adding the following code after the SayHelloTo method:
Sub Wrong()
Dim myInteger As Integer
Dim myString As String = "43"
myInteger = myString
Console.WriteLine(myInteger)
myString = "Banjo"
myInteger = myString
Console.WriteLine(myInteger)
End Sub
This method attempts to assign a string value (myString) to an integer variable (myInteger), with different values in myString. The first time, myString contains a string that can be converted to a number, so Visual Basic converts the string to an integer and assigns that value to myInteger. On the second occasion, myString contains the value "Banjo" which can’t be converted to a number. When the program runs, this conversion will fail and the program will stop running. The following steps show what happens when you try:
Add the following line of code (italic) into the Main subroutine:
Sub Main()
SayHelloWorld()
SayHelloTo("Eric")
SayHelloTo("Sandra")
Wrong()
End Sub
Press Ctrl-F5 to run the program without debugging.
At first, a few lines appear on the console as usual:
Then, a dialog box appears that indicates a problem (your dialog box may look slightly different than this):
Click the red X at the top right to dismiss the dialog box. Finally, several messages are displayed in the console, which provide details about the error that occurred. Press any key to close the console window.
You can ignore most of the error text for the time being; but notice that the first line of the error message states:
Conversion from string "Banjo" to type 'Integer' is not valid.
This is our clue as to what has happened to cause this error. The message tells us that the conversion is not valid – which is not surprising, because "Banjo" isn’t a number!
If you examine the entire console output, you can glean some more information by seeing how much of the program worked successfully before the error occurred. In this case, you can see the number 43 printed right before the error text. It’s a pretty good bet that the first Console.WriteLine statement inside the Wrong subroutine printed this number – so we can assume that the first conversion, from the string "43" to an integer, was successful.
The moral of this tale is that you need to be careful when you mix data types, because your program can fall over while it’s running if you get things wrong. The simplest rule of thumb is that you should never assign variables from one data type to another without performing a conversion first – don’t rely on it happening automatically!
Now you have seen what happens when you try to mix data types, you should delete the Wrong method from the program, and delete the line in Main that calls Wrong. Run the program again to check that it works correctly.
The SayHelloTo Method Revisited
Now you understand what a variable is, let’s take another look at the SayHelloTo subroutine to get a deeper understanding of how it works.
Sub SayHelloTo(ByVal toWhom As String)
Dim message As String
message = "Hello, " & toWhom
Console.WriteLine(message)
End Sub
The first line is the subroutine header, and tells us the name of the subroutine, along with what parameters it expects a caller to provide. In this case, the SayHelloTo method expects a parameter with a string type (“As String)”), which is identified by the name toWhom. ByVal is a special keyword that only appears in parameter lists – you can ignore it for the time being.
The ByVal keyword actually specifies that the value of the variable underlying the parameter is not changed by the subroutine. If you omit this keyword, and you make a change to the value of the parameter variable inside your subroutine, then your subroutine will change the value of the variable that was passed in to the subroutine.
The first statement in the method body declares another string variable, called message. The Dim keyword lets the computer know that you are about to declare a variable. If you are declaring more than 1 variable, it is good form to put all your Dim statements at the beginning of the subroutine in which you will use these variables.
The Dim keyword is an abbreviation of the word ‘Dimension.’ The name refers to the size (or dimension) of the space in memory that is set aside for the variable.
The second statement assigns a value to the message variable that consists of the string "Hello, " joined to the value of the toWhom variable. The ampersand sign “&” operator is used to append string values together. So if the caller of the method passes a parameter of "Eric" when it calls SayHelloTo, then the variable message will have a value of "Hello, Eric" after this statement has executed.
The third statement is our old friend Console.WriteLine. There is a subtle difference here from how we’ve used it previously, however. Notice that there are no quotation marks around message. This is because we are passing the value inside the message variable, not the actual string "message", as a parameter to the Console.WriteLine method.
To see the effect of this subtle but important difference, change the second statement so that it reads Console.WriteLine("message") - including the quotation marks - and run the program again without debugging. This time, the output from the SayHelloTo method is not what we intended:
Because of the enclosing quotation marks, the compiler has used the literal string "message" instead of the value of the message variable as a parameter to Console.WriteLine. We don’t want SayHelloTo to work like this, so go ahead and remove the quotes around message, then run the program to check it’s working correctly.
Functions - Subroutines That Produce Output Values
So far, the subroutines you have written simply perform some actions on behalf of your program. By using variables and parameters, a subroutine can perform the same action with different data. But you can also write methods that calculate a value and send that value back to the caller – these are called functions. The main difference between subroutines and functions is that functions must return an output value.
You can think of a method as an action or set of actions grouped together. So, when you brush your teeth in the morning, you can think of the ‘Brushing Teeth Procedure’ as a method. We talk about 2 types of methods in this guide: Subroutines and Functions. Both of these types of methods may take an input (toothbrush, toothpaste, teeth), and do something with the input (brush teeth). The main difference between Subroutines and Functions is that a Function has an Output value as well. So the ‘Brushing Teeth’ method may be a Subroutine, and a ‘Make Toast’ method may be a Function since the input is bread, and the output is toast.
Add the following code right after the SayHelloTo subroutine:
Function CalculateGreeting(ByVal toWhom As String) As String
Dim message As String = "Hello, " & toWhom
Return message
End Function
There are two important differences between this function and the SayHelloTo subroutine. The first is in the header – instead of saying Sub it says Function. This tells the compiler that CalculateGreeting produces an output value. The last part of the header (italic below) tells the compiler that the output from CalculateGreeting has a String data type.
Function CalculateGreeting(ByVal toWhom As String) As String
The other difference is in the last statement in the function, which reads
The Return keyword indicates the value that the function should return to the caller – in this case, the value to return is the contents of the message variable. The value returned by a function is called the return value or result.
What the CalculateGreeting function does is to perform a calculation, and then send the result of the calculation back to the code that called the function.
Now modify the second statement in the SayHelloTo subroutine as italics below, so that it reads:
Sub SayHelloTo(ByVal toWhom As String)
Dim message As String
message = CalculateGreeting(toWhom)
Console.WriteLine(message)
End Sub
The added expression is a function call, which works like when you called the SayHelloTo subroutine from the Main subroutine. The difference is that, with this function, the program takes the result of CalculateGreeting and assigns that value to the message variable. Run the program to check that it works, and that you still see the same console output as before.