Visual Basic Functions and Subroutines
Functions and Subroutines give your Visual Basic programs structure and shape. And just like Loops in Visual Basic, effective use of Functions and Subs allow you to efficiently control the flow of execution of your code. Fully understanding Functions and Procedures correctly will allow you to code in the most efficient way possible. Understanding Functions and Subroutines will allow you to obey the DRY principle (Do Not Repeat Yourself), 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. If you have code that loops through an array and this code needs to be utilised in a number of locations, the code to loop through the array 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 pi as Double Dim area as Double radius = 3 area = 3.142 * (radius ^ 2)
In this code, pi is accurate to 3 decimal places.
Now imagine we want to calculate the area of two circles
Dim radiusCircleOne as Double Dim areaCircleOne as Double Dim radiusCircleTwo as Double Dim areaCircleTwo as Double radiusCircleOne = 3 radiusCircleTwo = 2 areaCircleOne = 3.142 * (radiusCircleOne ^ 2) areaCircleTwo = 3.142 * (radiusCircleTwo ^ 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 such a bad thing? 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 do Visual Basic Functions and Subroutines solve this problem?
Look at the following code which does exactly the same job as the code above.
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 from a number of 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 made one amendment in one place. In the first example 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 too and is an excellent practise to start now, 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 had this code 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 available anywhere in my Project. There are other accessiblity levels but they are for a later date.
For now, when declaring a Subroutine or Function use the keywords
Public
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.”
Private
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.
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 like this
CalculateArea()
without passing two variables of type Double, I would have a compilation error from Visual Basic. In this case the routine needed the radius passed to it, and the area for it to calculate. 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
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.
In Summary
- 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!