Functions and Subroutines are tools to give your Visual Basic programs structure and shape. Just like Loops in Visual Basic, effective use of Functions and Subs allow you to efficiently control the flow of execution of your code. A full understanding of how to utilise Functions and Subs correctly will allow you to code in the most efficient way possible, allowing you to obey the DRY principle (Do Not Repeat Yourself). The DRY Principle is a delightful term I first read in the excellent (and much recommended book) The Pragmatic Programmer. The DRY principle states that every piece of knowledge must have a single, unambiguous, authoritative representation within a system. This is quite a statement so have a re-read. It essentially states that you should never repeat your code.
For example, lets imagine you have a piece of code that loops through an array. If this code needs to be utilised in a number of locations, rather than cutting and pasting this code throughout your application, the code should be written once and called a number of times within your application. How do we achieve this? Using Functions and Subs.
Think of Subroutines and Functions in Visual Basic as discrete blocks of code – blocks you can name and make use of anywhere in your Visual Basic application. For example, the area of a circle is ∏ r² (or ∏ * the radius squared).
Look at this following snippet of code which applies this formula:
Dim radius as Double Dim area as Double radius = 3 area = 3.142 * (radius ^ 2)
In this code, pi is accurate to 3 decimal places – 3.142.
Now imagine we want to calculate the area of two circles.
Dim radiusOne as Double Dim areaOne as Double Dim radiusTwo as Double Dim areaTwo as Double radiusOne = 3 radiusTwo = 2 areaOne = 3.142 * (radiusOne ^ 2) areaTwo = 3.142 * (radiusTwo ^ 2)
What do you notice in the above snippet of code? Think of the DRY principle. The means of calculating the area of the circle ∏ r², that piece of knowledge, has been repeated twice. Why is this bad? If I wanted to make the formula more accurate by applying pi to 5 decimal places, I would have to change the code in 2 places. In badly written large applications, this may have been repeated hundreds of times so I’d have to make hundreds of changes. If there was a bug in the calculation, I’d have a nightmare situation on my hands of making changes in hundreds of places, and debugging/testing the code in hundreds of places. Without applying the DRY principle, the code would become soon become completely unmaintainable.
So how would Functions and Subroutines solve this problem?
Look at the following code:
</span> <pre> Dim radiusOne as Double Dim areaOne as Double Dim radiusTwo as Double Dim areaTwo as Double radiusOne = 3 radiusTwo = 2 CalculateArea (radiusOne, areaOne) CalculateArea (radiusTwo, areaTwo) Private Sub CalculateArea (ByVal radius as Double, ByRef area as Double) area = 3.142 * radius ^ 2 End Sub
Although this achieves the exact same goal as the first example, the DRY principle has been obeyed. No code has been repeated. I have created a SubRoutine called CalculateArea and called that code in two places.
The syntax for a Subroutine is:
Sub SubroutineName (parameter list) Code End Sub
In this case the SubRoutine code is as follows:
Private Sub CalculateArea (ByVal radius as Double, ByRef area as Double) area = 3.142 * radius ^ 2 End Sub
And I called this code in two places using the syntax:
CalculateArea (radiusOne, areaOne)
Say, for example, that pi to three decimal places doesn’t suffice. There is a more accurate way to calculate pi, by dividing 355/113, which is accurate to 6 decimal places. I can modify the routine CalculateArea as follows:
Private Sub CalculateArea (ByVal radius as Double, ByRef area as Double) Dim pi as Double pi = 355/113 area = pi * radius ^ 2 End Sub
Now my entire application is more accurate and I only amended one area of my application. Without Subroutines I would have to adjust two areas of code. In large badly written applications I’ve seen these amendments in the 1000′s. DRY is definitely a principle you want to adhere to and is an excellent discipline to start now, this early in your coding career.
Anyhow there were a couple of other interesting new keywords to define this Subroutine.
The Subroutine was declared Private. Private is a keyword that means the routine is only available where it is defined. If this code was in a Visual Basic Form, the Subroutine wouldn’t be accessible outside of that Visual Basic Form. If I had given the routine the keyword Public, the routine would be accessible anywhere in my Visual Basic application. There are other accessibility levels but they are for a later date.
For now, when declaring a Subroutine or Function use the keywords
Which Microsoft describes as, “The Public (Visual Basic) keyword in the declaration statement specifies that the elements are accessible from code anywhere within the same project, from other projects that reference the project, and from any assembly built from the project. The following code shows a sample Public declaration.”
In other words, your routine or variable is accessible anywhere in your application.
Which Microsoft describes as, “The Private (Visual Basic) keyword in the declaration statement specifies that the elements are accessible only from within the same module, class, or structure. The following code shows a sample Private declaration”.
In other words, the routine or variable is accessible within the module, class or form it was declared.
You’ll also notice the routine has a name that specifies exactly what the routine does. This is absolutely essential and another key tenet of DRY, that the item of knowledge, the routine, is clearly named. This will be invaluable to you when you come to an old piece of code that you need to amend in some way. Rather than working out what the routine does, the name describes it exactly.
After the name of the routine you’ll see a couple of parameters passed to the routine, a Double called radius and a Double called area.
Private Sub CalculateArea (ByVal radius as Double, ByRef area as Double)
To call the routine I would have to pass two variables of type Double for the routine to function. If I called the routine without passing two variables of type Double, I would receive a compilation error from Visual Basic.
In this case the routine needs two variables, one representing the radius and the other representing the area, passed to it. Once passed, I can use these parameters as variables local to my routine.
I declared one parameter ByVal and one ByRef. ByVal instructs Visual Basic that the routine CalculateArea cannot modify the value of the parameters. The routine could manipulate this number but the variables passed in the calling code will not be affected. Visual Basic essentially creates copies of the variables. ByRef on the other hand instructs Visual Basic that CalculateArea can modify the value of the variables areaOne and areaTwo and these changes will be passed back to the calling code.
By default I would always use ByVal unless there is a specific need to do so. In this case, there was a specific need to allow the variable area to be modified – area is the output of the routine. This isn’t immediately apparent however. The parameter area could be used for anything; there is no way to know (unless you wrote the routine) that the area parameter was actually the return value of the routine. If an output of your routine is a value, in this case the area of the circle, there is a better way to achieve this goal – by using a Function.
Look at the example again:
</span> <pre> Dim radiusOne as Double Dim areaOne as Double Dim radiusTwo as Double Dim areaTwo as Double radiusOne = 3 radiusTwo = 2 areaOne = CalculateArea( radiusOne ) areaTwo = CalculateArea( radiusTwo ) Private Function CalculateArea (ByRef radius as Double) As Double Dim pi as Double pi = 355/113 Return pi * radius ^ 2 End Sub
I’ve declared CalculateArea as a Function as opposed to a Sub. A Function is essentially a Sub that returns a value.
Look at the declaration:
Private Function CalculateArea (ByRef radius as Double) As Double
I’ve stated that the Function CalculateArea will return a Double – and the name of the routine implies that the output of the routine will be the area of a circle. The body of code calculates the area as before but rather than using a ByRef parameter, the Function itself will return the area.
The syntax to call the Function is as follows:
area = CalculateArea( radius )
A local variable of type Double is populated with the return value of the Function.
Back to the Function itself, look at the last line:
Return pi * radius ^ 2
This instructs Visual Basic that the Function will return the value of pi * radius squared.
- Functions and Routines help you obey the DRY Principle of not repeating your code
- Functions and Subroutines will make your code easier to write and maintain
- Use a Function when the output of the routine is a value. Use a Subroutine when no output is required, or more than one output is required.
By this stage you’re really getting to grips with the absolute fundamentals of coding, in Visual Basic or any other language, so well done and keep going! If you’re still not 100% sure, don’t worry, the video tutorial explains all.