You are on page 1of 12

Sub and Function Procedures

Subs and Functions are blocks of code in your program that are called upon from other parts of your
program. Subs and Functions are the building blocks of a program and provide a way to organize and
modularize your code.
The difference between a Sub and a Function is that a Sub does not produce a return value (i.e., one that
can be assigned directly to a variable, whereas a Function does produce a return value). Both Subs and
Functions can be called with or without parameters.
Calling a Sub Without Parameters
The statement below calls a Sub named "AddEm" (you "call" or invoke a Sub by specifying its name
followed by parentheses):
AddEm()
The Sub "AddEm" would be a section of code in this format:
Private Sub AddEm()
[statements]
End Sub
When the statement "AddEm()" is executed, VB would execute the statements in the Sub named
"AddEm" and then return to the statement the followed "AddEm()".
Example (Calling a Sub Without Parameters)
When the sample program below is run, the user is prompted to enter two numbers. The Addem Sub is
called, which performs the addition. Program flow then returns to the Console.WriteLine statement, which
displays the sum of the two numbers.
Note that the variables involved are declared at the module-level (i.e., general declarations section, or the
section of the module prior to any Subs or Functions) because the variables are common to both the main
method and the AddEm Sub procedure.
Code:
Module Module1
'Module-level variables are needed for this example
Private mintNum1 As Integer
Private mintNum2 As Integer
Private mintSum As Integer
Sub Main()
Console.Write("Enter first number: ")
mintNum1 = Val(Console.ReadLine())
Console.Write("Enter second number: ")
mintNum2 = Val(Console.ReadLine())
AddEm()

Console.WriteLine("The sum is: {0}", mintSum)


Console.WriteLine("")
Console.WriteLine("(Press Enter to close this window.)")
Console.ReadLine()
End Sub
Private Sub AddEm()
mintSum = mintNum1 + mintNum2
End Sub
End Module
Screen-shot:

Download the project code for the example above here.


Calling a Sub With Parameters
More often than not, a Sub procedure will be expecting one or more parameters. This enhances the
reusability and flexibility of the Sub procedure. The syntax for a Sub procedure is:
[Private | Public] Sub SubName[(parameter list)]
[statements]
End Sub

where "parameter list" is a comma-separated list of the parameter variables with their data types
(i.e., var1 As datatype, var2 As datatype, etc.).
For example, if we were to modify the "AddEm" Sub to accept three Integer variables, the header for the
"Addem" Sub would look like this:
Private Sub AddEm(pintNum1 As Integer, pintNum2 As Integer, pintSum As
Integer)
The call to AddEm must now specify, or pass, three integer variables to the Sub
AddEm(intNum1, intNum2, intSum)
The important thing is that the argument list of the calling statement must match the parameter list of the
Sub procedure one-for-one in terms of both the number of variables passed and the data types of the
variables passed. The names of the corresponding argument/parameter variables can be (and often are)
different. With the naming conventions used in these tutorials, the variable names of the parameters in a
Sub or Function header start with the letter "p" for "parameter".
Example (Calling a Sub With Parameters)
In the sample program below, as in the previous example, the user is prompted to enter two numbers.
The Addem Sub is called, which performs the addition. Program flow then returns to the
Console.WriteLine statement, which displays the sum of the two numbers.
The difference this time is that the three variables (the two addends and the sum) are passed as
arguments to the Sub Addem. When the call is made, the Sub Addem adds pintNum1 and pintNum2,
storing the result in pintSum. When program flow returns to the Console.WriteLine statement, the value
of pintSum that was calculated in AddEm is available in its counterpart intSum. (It is important that the
keyword ByRef precede pintSum in the header for the Sub Addem procedure. The meaning of ByRef and
ByVal is explained a little later below.)
The variables involved are declared at the local level (i.e., in the main method, rather than in the general
declarations section). A general rule-of-thumb is that variables should be as limited in scope as possible.
Code:
Module Module1
Sub Main()
'The variables can be declared at the local level
Dim intNum1 As Integer
Dim intNum2 As Integer
Dim intSum As Integer
Console.Write("Enter first number: ")
intNum1 = Val(Console.ReadLine())
Console.Write("Enter second number: ")
intNum2 = Val(Console.ReadLine())
AddEm(intNum1, intNum2, intSum)
Console.WriteLine("The sum is: {0}", intSum)
Console.WriteLine("")
Console.WriteLine("(Press Enter to close this window.)")
Console.ReadLine()

End Sub
Private Sub AddEm(ByVal pintNum1 As Integer, ByVal pintNum2 As Integer,
ByRef pintSum As Integer)
pintSum = pintNum1 + pintNum2
End Sub
End Module

When this example is run, it will behave exactly the same as the previous example.
Download the project code for the example above here.
ByRef vs. ByVal
As indicated in the examples above, variables can be passed to a subroutine "by reference" or "by value",
which are specified with the ByRef or ByVal keyword, respectively. The default in VB.NET is "by value".
(This is a change from previous versions of VB, where the default was "by reference".)
The differences are as follows:

When variables are passed by reference, only the memory addresses of the variables are
passed. This means that the values passed can be modified by the subroutine and would have
the new value after the subroutine exits and returns control to the calling program. Important: A
variable that is expected to contain a "return" value or output value must be passed by reference.

When variables are passed by value, a copy of the variable is passed. This means that even if
the values passed are modified by the subroutine, those modified values remain local to that
subroutine. When the subroutine exits and returns control to the calling program, the variables
that were passed by value retain the value they originally had before the call. Appropriate
variables to pass by value would be "input" values to the subroutine. "Input" values to the
subroutine can be passed either by reference or by value; it would be "proper" to pass them by
value. As long as the subroutine does not modify the input variables, there is no "harm" in
passing them by reference. Be advised that you take a bit of a performance hit when you pass
subroutine arguments by value passing by reference is faster.

Calling a Function
To call a Function, the syntax is identical to an assignment statement that uses a VB built-in function:
VariableName = FunctionName[(argument list)]
For example, if I made a function called "AddEm" that returned a value (like the sum, for example), I could
invoke the function as follows:
intSum = AddEm(intNum1, intNum2)
The above statement would cause the following to happen:
The procedure AddEm would be called, passing intNum1 and intNum2
The AddEm procedure would add the values of intNum1 and intNum2 to produce its return value,
the sum.

When the AddEm procedure exits, its return value would be stored in the variable intSum

The (simplified) format of the function procedure itself is:


[Private | Public] Function FunctionName[(parameter list)] [As datatype]
[statements]
FunctionName = value
[statements]
End Function
- or [Private | Public] Function FunctionName[(parameter list)] [As datatype]
[statements]
Return value
[statements]
End Function

Note that to return a value from a function, you can either assign the value to the function name or include
it in a Return statement. When you assign the return value to the function name, any statements
following the assignment statement will be executed before returning to the caller. When you assign the
return value using the Return statement, control will immediately return to the caller and any remaining
statements in the function procedure will be ignored.
Note:

In previous versions of VB, the return value of a function could only be set via the first method
discussed above (i.e., by assigning the return value to the function name). The Return statement
was not used to set the return value of a function (the Return statement exists in previous
versions of VB, but its purpose is to return control from a block of code executed by the GoSub
statement, which is no longer supported in VB.NET).

As when calling a Sub, the items passed in the argument list of the call to the Function must match the
parameter list of the Function header in number and datatypes. The datatype of the return value must
match the datatype of the target variable name in the assignment statement that calls the Function.
Following is the code to implement "AddEm" as a function:
Example (Calling a Function)
Module Module1
Sub Main()
'The variables can be declared at the local level
Dim intNum1 As Integer
Dim intNum2 As Integer
Dim intSum As Integer
Console.Write("Enter first number: ")
intNum1 = Val(Console.ReadLine())
Console.Write("Enter second number: ")
intNum2 = Val(Console.ReadLine())

intSum = AddEm(intNum1, intNum2)


Console.WriteLine("The sum is: {0}", intSum)
Console.WriteLine("")
Console.WriteLine("(Press Enter to close this window.)")
Console.ReadLine()
End Sub
Private Function AddEm(ByVal pintNum1 As Integer, _
ByVal pintNum2 As Integer) _
As Integer
Return (pintNum1 + pintNum2)
End Function
End Module

When this example is run, it will behave exactly the same as the previous two examples.
Download the project code for the example above here.
Functions That Return Boolean Values
Consider the following function, called IsOdd, which determines whether or not a number is odd:
Private Function IsOdd(ByVal pintNumberIn As Integer) As Boolean
If (pintNumberIn Mod 2) = 0 Then
Return False
Else
Return True
End If
End Function

Now consider the following section of code that calls this function:
Sub Main()
Dim intNumIn As Integer
Console.Write("Enter a number: ")
intNumIn = Val(Console.ReadLine())
If IsOdd(intNumIn) Then
Console.WriteLine("The number that you entered is odd.")
Else
Console.WriteLine("The number that you entered is not odd.")
End If
Console.WriteLine("")
Console.WriteLine("(Press Enter to close this window.)")
Console.ReadLine()
End Sub

Screen-shot:

Download the project code for the example above here.


Using Optional Arguments
VB allows you to create Subs or Functions that have optional arguments i.e., arguments that may or
may not be passed; and if not passed will assume a default value. Optional arguments are specified in the
procedure header with keyword Optional. All Optional arguments must be placed at the end of the
argument list (they must follow any required arguments). Optional arguments that are not passed will
take on default values. The default value of an Optional argument must be set by assigning the optional
argument a value in the procedure header. For example, the procedure header
Private Sub MySub(pblnFlag As Boolean, Optional plngNumber As Long = 0)
specifies that the last argument is Optional. Any call to MySub must pass it at least one argument (a
Boolean) in order to avoid an error. If the caller so chooses, a second argument (a Long) can also be
passed to MySub. Consider the following calls to MySub:
MySub
' Error: Required argument is missing
MySub (True)
' OK required argument is passed
MySub (False, 10) ' OK both required and optional arguments passed
In this case, if the argument for plngNumber is not passed, it will have the default value of 0; otherwise, it
will have the value of whatever was passed. Default values can only be used with Optional arguments.
Following is an example using a Sub that takes in three Optional arguments with default values. The Sub
calculates the gross pay of an employee:
Code:
Module Module1

Sub Main()
Console.WriteLine("Hours".Trim.PadLeft(11) & _
"Base Rate".Trim.PadLeft(11) & _
"O/T Rate".Trim.PadLeft(11) & _
"Base Pay".Trim.PadLeft(11) & _
"O/T Pay".Trim.PadLeft(11) & _
"Gross Pay".Trim.PadLeft(11))
Console.WriteLine("------".Trim.PadLeft(11) & _
"----------".Trim.PadLeft(11) & _
"---------".Trim.PadLeft(11) & _
"---------".Trim.PadLeft(11) & _
"--------".Trim.PadLeft(11) & _
"----------".Trim.PadLeft(11))
CalcGrossPay()
' Default all three arguments
CalcGrossPay(25)
' Default rightmost two arguments
CalcGrossPay(42, 30)
' Default rightmost argument
CalcGrossPay(43, 28, 1.1)
' Pass all three arguments
CalcGrossPay(40, , 1)
' Default second argument
CalcGrossPay(, 37)
' Default first and third arguments
CalcGrossPay(, , 1.25)
' Default first two arguments
Console.WriteLine("")
Console.WriteLine("(Press Enter to close this window.)")
Console.ReadLine()
End Sub
Private Sub CalcGrossPay(Optional ByVal pintHoursWorked As Integer = 40, _
Optional ByVal psngBaseHourlyRate As Single = 35, _
Optional ByVal psngOvertimeRate As Single = 1.5)
Dim sngBasePay As Single
Dim sngOvertimePay As Single
Dim sngGrossPay As Single
If pintHoursWorked <= 40 Then
sngBasePay = psngBaseHourlyRate * pintHoursWorked
sngOvertimePay = 0
Else
sngBasePay = psngBaseHourlyRate * 40
sngOvertimePay = (pintHoursWorked - 40) * psngBaseHourlyRate * psngOvertimeRate
End If
sngGrossPay = sngBasePay + sngOvertimePay
Console.WriteLine(pintHoursWorked.ToString.Trim.PadLeft(11) & _
Format(psngBaseHourlyRate, "Fixed").Trim.PadLeft(11) & _
Format(psngOvertimeRate, "Fixed").Trim.PadLeft(11) & _
Format(sngBasePay, "Currency").Trim.PadLeft(11) & _
Format(sngOvertimePay, "Currency").Trim.PadLeft(11) & _
Format(sngGrossPay, "Currency").Trim.PadLeft(11))
End Sub
End Module

Screen-shot of the run:

Download the project code for the example above here.


The next example demonstrates the use of the IsNothing function, which can be used to test if an
Optional Object argument has been passed to a procedure. This example produces the same output as
the previous example (however, it is MUCH LESS EFFICIENT because it uses the generic "Object"
variable type, rather than specific variable types such as Integer and Single it is presented here for
demonstration purposes only):
Module Module1
Public Sub Main()
Console.WriteLine("Hours".Trim.PadLeft(11) & _
"Base Rate".Trim.PadLeft(11) & _
"O/T Rate".Trim.PadLeft(11) & _
"Base Pay".Trim.PadLeft(11) & _
"O/T Pay".Trim.PadLeft(11) & _
"Gross Pay".Trim.PadLeft(11))
Console.WriteLine("------".Trim.PadLeft(11) & _
"----------".Trim.PadLeft(11) & _
"---------".Trim.PadLeft(11) & _
"---------".Trim.PadLeft(11) & _
"--------".Trim.PadLeft(11) & _
"----------".Trim.PadLeft(11))
CalcGrossPay()
' Default all three arguments
CalcGrossPay(25)
' Default rightmost two arguments
CalcGrossPay(42, 30)
' Default rightmost argument
CalcGrossPay(43, 28, 1.1) ' Pass all three arguments
CalcGrossPay(40, , 1)
' Default second argument
CalcGrossPay(, 37)
' Default first and third arguments
CalcGrossPay(, , 1.25)
' Default first two arguments
Console.WriteLine("")
Console.WriteLine("(Press Enter to close this window.)")

Console.ReadLine()
End Sub
Private Sub CalcGrossPay(Optional ByVal pobjHoursWorked As Object = Nothing, _
Optional ByVal pobjBaseHourlyRate As Object = Nothing, _
Optional ByVal pobjOvertimeRate As Object = Nothing)
Dim sngBasePay As Single
Dim sngOvertimePay As Single
Dim sngGrossPay As Single
If IsNothing(pobjHoursWorked) Then pobjHoursWorked = 40
If IsNothing(pobjBaseHourlyRate) Then pobjBaseHourlyRate = 35
If IsNothing(pobjOvertimeRate) Then pobjOvertimeRate = 1.5
If pobjHoursWorked <= 40 Then
sngBasePay = pobjBaseHourlyRate * pobjHoursWorked
sngOvertimePay = 0
Else
sngBasePay = pobjBaseHourlyRate * 40
sngOvertimePay = (pobjHoursWorked - 40) * pobjBaseHourlyRate * pobjOvertimeRate
End If
sngGrossPay = sngBasePay + sngOvertimePay
Console.WriteLine(pobjHoursWorked.ToString.Trim.PadLeft(11) & _
Format(pobjBaseHourlyRate, "Fixed").Trim.PadLeft(11) & _
Format(pobjOvertimeRate, "Fixed").Trim.PadLeft(11) & _
Format(sngBasePay, "Currency").Trim.PadLeft(11) & _
Format(sngOvertimePay, "Currency").Trim.PadLeft(11) & _
Format(sngGrossPay, "Currency").Trim.PadLeft(11))
End Sub
End Module

Note that data of any type can be assigned to an Object variable; in the procedure above, the default
numeric values are assigned to the optional Object variables. In previous versions of VB, the Variant data
type was used to hold any type of value; in VB.NET, the Variant data type is not supported, but the Object
data type assumes this functionality. In addition, previous versions of VB used the IsMissing function to
determine whether or not an optional Variant argument was passed to a procedure; in VB.NET, the
IsMissing function is not supported, but the IsNothing function assumes the functionality for testing
whether or not an optional Object argument has been passed to a procedure.
Download the project code for the example above here.
Using Named Arguments
The following example demonstrates the use of the named arguments, where you can specify the
arguments to be passed in the calling statement using the syntax
ArgumentName:=value
Using named arguments, the arguments to the procedure can be passed in any order. All required
arguments must be passed, but optional arguments can be omitted if desired. Using named arguments
saves coding when calling a procedure that has a lot of optional arguments but you only need to pass a
few of them.
Following is the code for GrossPay program using named arguments:

Module Module1
Sub Main()
Console.WriteLine("Hours".Trim.PadLeft(11) & _
"Base Rate".Trim.PadLeft(11) & _
"O/T Rate".Trim.PadLeft(11) & _
"Base Pay".Trim.PadLeft(11) & _
"O/T Pay".Trim.PadLeft(11) & _
"Gross Pay".Trim.PadLeft(11))
Console.WriteLine("------".Trim.PadLeft(11) & _
"----------".Trim.PadLeft(11) & _
"---------".Trim.PadLeft(11) & _
"---------".Trim.PadLeft(11) & _
"--------".Trim.PadLeft(11) & _
"----------".Trim.PadLeft(11))
CalcGrossPay()
CalcGrossPay(pintHoursWorked:=25)
CalcGrossPay(pintHoursWorked:=42, psngBaseHourlyRate:=30)
CalcGrossPay(pintHoursWorked:=43, psngBaseHourlyRate:=28, psngOvertimeRate:=1.1)
CalcGrossPay(pintHoursWorked:=40, psngOvertimeRate:=1)
CalcGrossPay(psngBaseHourlyRate:=37)
CalcGrossPay(psngOvertimeRate:=1.25)
Console.WriteLine("")
Console.WriteLine("(Press Enter to close this window.)")
Console.ReadLine()
End Sub
Private Sub CalcGrossPay(Optional ByVal pintHoursWorked As Integer = 40, _
Optional ByVal psngBaseHourlyRate As Single = 35, _
Optional ByVal psngOvertimeRate As Single = 1.5)
Dim sngBasePay As Single
Dim sngOvertimePay As Single
Dim sngGrossPay As Single
If pintHoursWorked <= 40 Then
sngBasePay = psngBaseHourlyRate * pintHoursWorked
sngOvertimePay = 0
Else
sngBasePay = psngBaseHourlyRate * 40
sngOvertimePay = (pintHoursWorked - 40) * psngBaseHourlyRate * psngOvertimeRate
End If
sngGrossPay = sngBasePay + sngOvertimePay
Console.WriteLine(pintHoursWorked.ToString.Trim.PadLeft(11) & _
Format(psngBaseHourlyRate, "Fixed").Trim.PadLeft(11) & _
Format(psngOvertimeRate, "Fixed").Trim.PadLeft(11) & _
Format(sngBasePay, "Currency").Trim.PadLeft(11) & _
Format(sngOvertimePay, "Currency").Trim.PadLeft(11) & _
Format(sngGrossPay, "Currency").Trim.PadLeft(11))
End Sub
End Module

Download the project code for the example above here.

Exiting a Sub or Function Early


If you need to exit a Sub or Function procedure "early", you can use the Exit Sub or Exit
Function statements, respectively.
Example:
Dim intNumIn As Integer
Console.WriteLine("Enter a non-zero number: ")
intNumIn = Val(Console.ReadLine())
If intNumIn = 0 Then
Console.WriteLine ("You entered zero or a non-numeric value.")
Exit Sub
End If
' processing will continue here only if a non-zero number was entered
Console.WriteLine "The number you entered was: " & intNumIn
' do some other stuff

You might also like