There are situations in which the same function must operate on different data types or a different number of arguments. In the past, you had to write different functions, with different names and different arguments, to accommodate similar requirements. The Framework introduced the concept of function overloading, which means that you can have multiple implementations of the same function, each with a different set of arguments and possibly a different return value. Yet all overloaded functions share the same name. Let me introduce this concept by examining one of the many overloaded functions that come with the .NET Framework.
The Next method of the System.Random class returns an integer value from –2,147,483,648 to 2,147,483,647. (This is the range of values that can be represented by the Integer data type.) We should also be able to generate random numbers in a limited range of integer values. To emulate the throw of a die, we want a random value in the range from 1 to 6, whereas for a roulette game we want an integer random value in the range from 0 to 36. You can specify an upper limit for the random number with an optional integer argument. The following statement will return a random integer in the range from 0 to 99:
randomInt = rnd.Next(100)
Code language: VB.NET (vbnet)
You can also specify both the lower and upper limits of the random number’s range. The following statement will return a random integer in the range from 1,000 to 1,999:
randomInt = rnd.Next(1000, 2000)
Code language: VB.NET (vbnet)
The same method behaves differently based on the arguments we supply. The behavior of the method depends either on the type of the arguments, the number of the arguments, or both. As you will see, there’s no single function that alters its behavior based on its arguments. There are as many different implementations of the same function as there are argument combinations. All the functions share the same name, so they appear to the user as a single multifaceted function. These functions are overloaded, and you’ll see how they’re implemented in the following section.
If you haven’t turned off the IntelliSense feature of the editor, as soon as you type the opening parenthesis after a function or method name, you see a yellow box with the syntax of the function or method. You’ll know that a function, or a method, is overloaded when this box contains a number and two arrows. Each number corresponds to a different overloaded form, and you can move to the next or previous overloaded form by clicking the two little arrows or by pressing the arrow keys.
Let’s return to the Min() function we implemented earlier in this chapter. The initial implementation of the Min() function is shown next:
Function Min(ByVal a As Double, ByVal b As Double) As Double
Min = IIf(a < b, a, b)
End Function
Code language: VB.NET (vbnet)
By accepting Double values as arguments, this function can handle all numeric types. VB 2008 performs automatic widening conversions (it can convert Integers and Decimals to Doubles), so this trick makes the function work with all numeric data types. However, what about strings? If you attempt to call the Min() function with two strings as arguments, you’ll get an exception. The Min() function just can’t handle strings.
To write a Min() function that can handle both numeric and string values, you must, in essence, write two Min() functions. All Min() functions must be prefixed with the Overloads keyword. The following statements show two different implementations of the same function:
Overloads Function Min(ByVal a As Double, ByVal b As Double) As Double
Min = Convert.ToDouble(IIf(a < b, a, b))
End Function
Overloads Function Min(ByVal a As String, ByVal b As String) As String
Min = Convert.ToString(IIf(a < b, a, b))
End Function
Code language: VB.NET (vbnet)
We need a third overloaded form of the same function to compare dates. If you call the Min() function, passing as an argument two dates, as in the following statement, the Min() function will compare them as strings and return (incorrectly) the first date.
Debug.WriteLine(Min(#1/1/2009#, #3/4/2008#))
Code language: VB.NET (vbnet)
This statement is not even valid when the Strict option is on, so you clearly need another overloaded form of the function that accepts two dates as arguments, as shown here:
Overloads Function Min(ByVal a As Date, ByVal b As Date) As Date
Min = IIf(a < b, a, b)
End Function
Code language: VB.NET (vbnet)
If you now call the Min() function with the dates #1/1/2009# and #3/4/2008#, the function will return the second date, which is chronologically smaller than the first.
Let’s look into a more complicated overloaded function, which makes use of some topics discussed later in this tutorial. The CountFiles() function counts the number of files in a folder that meet certain criteria. The criteria could be the size of the files, their type, or the date they were created. You can come up with any combination of these criteria, but the following are the most useful combinations. (These are the functions I would use, but you can create even more combinations or introduce new criteria of your own.) The names of the arguments are self-descriptive, so I need not explain what each form of the CountFiles() function does.
CountFiles(ByVal minSize As Integer, ByVal maxSize As Integer) As Integer
CountFiles(ByVal fromDate As Date, ByVal toDate As Date) As Integer
CountFiles(ByVal type As String) As Integer
CountFiles(ByVal minSize As Integer, ByVal maxSize As Integer, _
ByVal type As String) As Integer
CountFiles(ByVal fromDate As Date, ByVal toDate As Date, _
ByVal type As String) As Integer
Code language: VB.NET (vbnet)
Listing 3.10 shows the implementation of these overloaded forms of the CountFiles() function. (I’m not showing all overloaded forms of the function; you can open the OverloadedFunctions project in the IDE and examine the code.) Because we haven’t discussed file operations yet, most of the code in the function’s body will be new to you — but it’s not hard to follow. For the benefit of readers who are totally unfamiliar with file operations, I included a statement that prints in the Immediate window the type of files counted by each function. The Debug.WriteLine statement prints the values of the arguments passed to the function, along with a description of the type of search it will perform. The overloaded form that accepts two integer values as arguments prints something like this:
You've requested the files between 1000 and 100000 bytes
Code language: VB.NET (vbnet)
whereas the overloaded form that accepts a string as an argument prints the following:
You've requested the .EXE files
Code language: VB.NET (vbnet)
Listing 3.10: The Overloaded Implementations of the CountFiles() Function
Overloads Function CountFiles( _
ByVal minSize As Integer, _
ByVal maxSize As Integer) As Integer
Debug.WriteLine("You’ve requested the files between " & _
minSize & " and " & maxSize & " bytes")
Dim files() As String
files = System.IO.Directory.GetFiles("c:\windows")
Dim i, fileCount As Integer
For i = 0 To files.GetUpperBound(0)
Dim FI As New System.IO.FileInfo(files(i))
If FI.Length >= minSize And FI.Length <= maxSize Then
fileCount = fileCount + 1
End If
Next
Return(fileCount)
End Function
Overloads Function CountFiles( _
ByVal fromDate As Date, _
ByVal toDate As Date) As Integer
Debug.WriteLine("You’ve requested the count of files created from " & _
fromDate & " to " & toDate)
Dim files() As String
files = System.IO.Directory.GetFiles("c:\windows")
Dim i, fileCount As Integer
For i = 0 To files.GetUpperBound(0)
Dim FI As New System.IO.FileInfo(files(i))
If FI.CreationTime.Date >= fromDate And _
FI.CreationTime.Date <= toDate Then
fileCount = fileCount + 1
End If
Next
Return(fileCount)
End Function
Overloads Function CountFiles(ByVal type As String) As Integer
Debug.WriteLine("You’ve requested the " & type & " files")
' Function Implementation
End Function
Overloads Function CountFiles( _
ByVal minSize As Integer, _
ByVal maxSize As Integer, _
ByVal type As String) As Integer
Debug.WriteLine("You’ve requested the " & type & _
" files between " & minSize & " and " & _
maxSize & " bytes")
' Function implementation
End Function
Overloads Function CountFiles(ByVal fromDate As Date, _
ByVal toDate As Date, ByVal type As String) As Integer
Debug.WriteLine("You’ve requested the " & type & _
" files created from " & fromDate & " to " & toDate)
' Function implementation
End Function
Code language: VB.NET (vbnet)
If you’re unfamiliar with the Directory and File objects, focus on the statement that prints to the Immediate window and ignore the statements that actually count the files that meet the specified criteria. After reading Chapter, “Accessing Folders and Files,” you can revisit this example and understand the statements that select the qualifying files and count them.
Start a new project and enter the definitions of the overloaded forms of the function on the form’s level. Listing 3.10 is lengthy, but all the overloaded functions have the same structure and differ only in how they select the files to count. Then place a TextBox and a button on the form, as shown in Figure 3.2, and enter a few statements that exercise the various overloaded forms of the function (such as the ones shown in Listing 3.11) in the button’s Click event handler.
Figure 3.2 – Overloaded Functions Example
Listing 3.11: Testing the Overloaded Forms of the CountFiles() Function
Private Sub Button1 Click(...) Handles Button1.Click
TextBox1.AppendText(CountFiles(1000, 100000) & _
" files with size between 1KB and 100KB" & vbCrLf)
TextBox1.AppendText(CountFiles(#1/1/2006#, #12/31/2006#) & _
" files created in 2006" & vbCrLf)
TextBox1.AppendText(CountFiles(".BMP") & " BMP files" & vbCrLf)
TextBox1.AppendText(CountFiles(1000, 100000, ".EXE") & _
" EXE files between 1 and 100 KB" & vbCrLf)
TextBox1.AppendText(CountFiles(#1/1/2006#, #12/31/2007#, ".EXE") & _
" EXE files created in 2006 and 2007")
End Sub
Code language: VB.NET (vbnet)
The button calls the various overloaded forms of the CountFiles() function one after the other and prints the results on the TextBox control. From now on, I’ll be omitting the list of arguments in the most common event handlers, such as the Click event handler, because they’re always the same and they don’t add to the readability of the code. In place of the two arguments, I’ll insert an ellipsis to indicate the lack of the arguments.
Figure 3.3 – The overloaded forms of the CountFiles() function
Function overloading is used heavily throughout the language. There are relatively few functions (or methods, for that matter) that aren’t overloaded. Every time you enter the name of a function followed by an opening parenthesis, a list of its arguments appears in the drop-down list with the arguments of the function. If the function is overloaded, you’ll see a number in front of the list of arguments, as shown in Figure 3.3. This number is the order of the overloaded form of the function, and it’s followed by the arguments of the specific form of the function. The figure shows all the forms of the CountFiles() function.