Learning the Visual Basic .NET Language - Functions and Subroutines
(Page 9 of 9 )
Functions and subroutines are the most basic building block you can use to organize your code. Ideally, each function or subroutine will perform a distinct, logical task. By breaking your code down into procedures, you not only simplify your life, but you also make it easier to organize your code into classes and step into the world of object-oriented programming.
Visual Basic distinguishes between two types of procedures: ordinary subroutines and functions. The only difference between the two is that functions return a value. To set the return value of a function, you can assign a value to the function name, just as in previous versions of Visual Basic. VB .NET also introduces the useful Return keyword, which allows you to exit a function and return a result in one quick, clear step.
Subroutines are declared with the Sub keyword, and functions are declared with the Function keyword. Here is an example of each one:
Private Sub MySub()
' Code goes here.
End Sub
Private Function MyFunc() As Integer
' As an example, return the number 10.
Return 10
End Function
You’ll notice that both of these procedures are preceded with the accessibility keyword Private. This indicates that these procedures won’t be accessible to code in a different class or module. The next chapter considers classes and accessibility in more detail.
Calling your procedures is straightforward—you simply enter the name of procedure, followed by parentheses. If you call a function, you have the option of using the data it returns, or just ignoring it.
' This call is allowed.
MySub()
' This call is allowed.
MyFunc()
' This call is allowed.
Dim MyNumber As Integer
MyNumber = MyFunc()
' This call isn't allowed.
' MySub does not return any information. MyNumber = MySub()
Parameters Procedures can also accept information through parameters. Parameters are declared in a similar way to variables. By convention, parameter names always begin with a lowercase first letter in any language.
Here’s how you might create a function that accepts two parameters and returns their sum.
Private Function AddNumbers(number1 As Integer, number2 As Integer) As Integer
Return (number1 + number2)
End Sub
When calling a procedure, you specify any required parameters in parentheses, or use an empty set of parentheses if no parameters are required.
' Call a subroutine with no parameters. MySub()
' Call a subroutine with two Integer parameters.
MySub2(10, 20)
' Call a function with two Integer parameters and an Integer return value.
Dim ReturnValue As Integer = AddNumbers(10, 10)
Procedure Overloading VB .NET supports overloading, which allows you to create more than one function or subroutine with the same name, but with a different set of parameters. When you call the procedure, the CLR automatically chooses the correct version by examining the parameters you supply.
This is old hat to C programmers, but a valuable new introduction to the Visual Basic world. It allows you to collect different versions of several functions together. For example, you might allow a database search that returns an author name. Rather than create three functions with different names depending on the criteria, such as GetNameFromID(), GetNameFromSSN(), GetNameFromBookTitle(), you could create three versions of the GetCustomerName() function. Each function would have the same name, but a different signature, meaning it would require different parameters.
To overload a procedure, you use the Overloads keyword. Here’s an example that provides two overloaded versions for the GetProductPrice() method.
Private Overloads Function GetProductPrice(ID As Integer) As Decimal
' Code here.
End Function
Private Overloads Function GetProductPrice(name As String) As Decimal
' Code here.
End Function
' And so on...
You can look up product prices based on the unique product ID, or the full product name, depending on whether you supply an integer or string argument:
Dim Price As Decimal
' Get price by product ID (the first version).
Price = GetProductPrice(1001)
' Get price by product name (the second version).
Price = GetProductPrice("DVD Player")
You cannot overload a function with versions that have the same signature—that is, the same number of parameters and parameter data types—because the CLR will not be able to distinguish them from each other. When you call an overloaded function, the version that matches the parameter list you supply is used. If no version matches, an error occurs.
NOTE .NET uses overloaded methods in most of its classes. This approach allows you to use a flexible range of different parameters, while centralizing functionality under common names. Even the methods we’ve looked at so far (like the String methods for padding or replacing text) have multiple versions that provide similar features with various different options.
Delegates
Delegates are a new feature of the .NET languages. They allow you to create a variable that “points” to a procedure. You can use this variable at any time to invoke the procedure. Delegates help you write flexible code that can be reused in many different situations.
The first step when using a delegate is to define its signature. A delegate variable can only point to a function or procedure that matches its specific signature (list of parameters). For example, if you have a subroutine that accepts a single string parameter, and another subroutine that accepts two string parameters, you’ll need to use a separate delegate type for each subroutine. This enforces a level of type safety that isn’t found with traditional function pointers in languages like C++.
Here’s the code you use to define a delegate and its signature:
' Define a delegate that can represent any function that accepts a single
' string parameter and returns a string. Private Delegate Function StringFunction(in As String) As String
Once you’ve defined a type of delegate, you can create and assign a delegate variable. For example, assume your program has the following function:
Private Function TranslateEnglishToFrench(english As String) As String
' Code goes here.
End Function
This function requires one string parameter and returns a string. Thus, it matches the signature used in the definition of the StringFunction delegate. That means you can create a StringFunction delegate variable, and use it to store a reference to the TranslateEnglishToFrench() function. To actually store the reference to the TranslateEnglishToFrench() function, you use the AddressOf statement.
The following code demonstrates this technique:
' Create a delegate variable.
Dim FunctionReference As StringFunction
' Store a reference to a matching procedure. FunctionReference = AddressOf TranslateEnglishToFrench
Once you have a delegate variable that references a function, you can invoke the function through the delegate. To do this, you just use the delegate name as though it were the function name:
Dim FrenchString As String
' Run the method that functionReference points to.
' In this case, it will be TranslateEnglishToFrench().
FrenchString = FunctionReference("Hello")
In the previous code example, the procedure that the FunctionReference delegate points to will be invoked with the parameter "Hello" and the return value will be stored in the FrenchString variable.
..........................................................................................................................
Delegates Are the Basis of Events
Wouldn’t it be nice to have a delegate that could refer to more than one function at once, and invoke them simultaneously? That would allow the client application to have multiple “listeners,” and notify the listeners all at once when something happens.
In fact, delegates do have this functionality, but you’re more likely to see it in use with .NET events. Events, which are described in the next chapter, are based on delegates, but work at a slightly higher level. In a typical ASP.NET program, you’ll use events extensively, but you’ll probably never work directly with delegates.
................................................................................................................................
The Last Word It’s impossible to do justice to an entire language in a single chapter. However, if you’ve programmed before, you’ll find that this chapter provides all the information you need to get started with the .NET languages. As you work through the full ASP.NET examples in the following chapters, you can refer to this chapter to clear up any language issues. In the next chapter, you’ll learn about more important language concepts, and the object-oriented nature of .NET.