Flylib.com

Books Software

 
 
 

Naming Variables


Naming Variables

VBScript has a few rules for what names you can give to a variable. The rules are pretty simple, and leave you plenty of room to come up with clear, useful, understandable variable names .

Note  

Rule Number 1: VBScript variable names must begin with an alpha character.

An alpha character is any character between 'a' and 'z' (capital or lowercase). Non-alpha characters are pretty much everything else: numbers , punctuation marks, mathematical operators, and other special characters. For example, these are legal variable names:

  • strName

  • Some_Thing

  • Fruit

And these are illegal variable names:

  • +strName

  • 99RedBalloons

  • @Test

    Note  

    Rule Number 2: Numbers and the underscore (_) character can be used within the variable name , but all other non- alphanumeric characters are illegal.

VBScript does not like variable names that contain characters that are anything but numbers and letters . The lone exception to this is the underscore (_) character. (Some programmers find the underscore character to be useful for separating distinct words within a variable name (for example, customer_name ), while other programmers prefer to accomplish this by letting the mixed upper and lower case letters accomplish the same thing (for example, CustomerName ). For example, these are legal variable names:

  • lngPosition99

  • Word1_Word2_

  • bool2ndTime

And these are illegal variable names:

  • str & Name

  • SomeThing@

  • First*Name

    Note  

    Rule Number 3: VBScript variable names cannot exceed 255 characters.

Hopefully, your variable names will not exceed 20 characters or so, but VBScript allows them to be as long as 255 characters.

These rules for variable naming should be pretty easy to follow, but it is important to make a distinction between coming up with variable names that are legal, and coming up with variable names that are clear, useful, and understandable. The fact that VBScript will allow you to use a variable name such as X99B2F012345 does not necessarily mean that it's a good idea to do so.

A variable name should make the purpose of the variable clear. If you're going to store the user 's name in a variable, a name like strUserName is a good one because it removes any doubt as to what the programmer intended the variable to be used for. Good variable names not only decrease the chances of errors creeping into your code, but also make the code itself easier for humans to read and understand.

Another principle that a large percentage of programmers have found useful is the 'Hungarian naming convention,' which we have mentioned a couple times before, and which we have been using throughout this and the preceding chapters. This convention simply involves using a prefix on the variable name to indicate what type of data the programmer intends for that variable to store.

For example, the variable name strUserName indicates not only that the variable should hold the user's name, but also that the subtype of the variable should be String . Similarly, the variable name lngFileCount indicates not only that the variable should hold a count of the number of files, but also that the subtype of the variable should be Long .

Appendix B of this book contains additional guidelines for naming variables, including a list of suggested data type prefixes.



Procedures and Functions

At this point we will introduce the concept of procedures and functions, which are essential building blocks for more complex scripts. Procedures and functions allow you to modularize the code in your script into named blocks of code that perform specific functions. Modularization allows you to think about a more complex problem in a structured way, increases the readability and understandability of your code, and creates opportunities to reuse the same code multiple times within the same script.

Sometimes the word procedure is used in the generic sense to refer to either a procedure or a function, but we will do our best in this chapter to use the term procedure in the specific sense. A function is a named block of code that returns a value to the calling code, while a procedure is a named block of code that does not return a value to the calling code. Let's break down some of the new concepts in that last sentence .

  • A named block of code : When we use the term block of code, we are referring to a grouping of lines of code that are related in some logical way, that work together to perform a certain programming task. We call procedures and functions 'named' blocks of code because we put an explicit boundary around the code and give it a name. For example, we might separate a block of code that processes a customer's order into a procedure with the name ProcessCustomerOrder() .

  • Calling code : When we say 'the calling code' we mean the code that calls a procedure or function. One of the primary purposes of naming a block of code is that other code can invoke that block of a code using the name. Throughout the preceding chapters, we have been looking at code that uses the MsgBox() procedure to display a value in a dialog box. The script code that invokes the MsgBox() procedure is referred to as the calling code , and MsgBox() is the procedure being called .

  • Returning a value : Some named blocks of code can return a value to the calling code. A procedure does not return a value, whereas a function does. Sometimes you need a value to be returned by a block of code, and sometimes you do not. As we have been using it, the MsgBox() procedure does not return a value (though it can if you ask it to- MsgBox() is interesting as it can be used as either a procedure or a function). We just pass MsgBox() a value to display, it displays the value to the user, and when the user clicks the OK button, the subsequent code continues executing. On the other hand, the CLng() function returns a value to the calling code. For example, in the code below we would say that the CLng() function is returning a value of 12 with the Long subtype and that returned value is stored in the lngCount variable.

    
    
    lngCount = CLng("12")
    
    
    

Procedure Syntax

A procedure is declared with the following syntax.

[PublicPrivate] Sub

Name

([Argument1],[ArgumentN])
    [code inside the procedure]
End Sub

A named block of code that is a procedure is identified with Sub keyword. ('Sub' is short for 'subprocedure,' which is another way of saying 'procedure.') You can optionally precede the Sub keyword with the keywords of Public or Private , but these keywords are really relevant only within a class where you want some procedures to be visible outside the class and other procedures to be not visible (see Chapter 8).

In a normal script file (that is, one that is not a class or a Windows Script Component), the keywords Public and Private do not really do anything for you since no procedures, functions, or variables can be visible to any other scripts in other files. If you do not specify one or the other, Public is the default.

The ending boundary of the procedure must be defined with the keywords End Sub . Between the Sub and End Sub boundaries, normal VBScript syntax rules apply.

The rules for naming a procedure are the same as those for naming variables (see earlier). It is a good idea, however, to use clear, purposeful names that make it obvious what the purpose of the procedure is and what the code inside of it does. A good technique is to use verb-noun combinations such as ProcessOrder or GetName .

Arguments (also known as parameters ) are optional for a procedure, and you can use as many arguments as you would practically need (though a procedure with too many arguments is a sure sign of a poorly designed procedure that is doing too much; see under section Design Strategies for Procedures and Functions ). An argument is a value that you wish to 'pass into' the procedure so that the code inside the procedure will have access to it. The argument list must be surrounded by parentheses, and arguments should be separated by commas if a procedure has more than one argument. If a procedure does not have any arguments, the parentheses after the procedure name should be omitted.

Here is a bare-bones procedure that does not use any arguments ( PROCEDURE_SIMPLE.VBS ).



Option Explicit




SayHelloToBill




Sub SayHelloToBill




MsgBox "Hello, Bill. Welcome to our script."




End Sub


The first line in this example is not part of the procedure definition, but rather is the calling code that invokes the procedure. A procedure just sits there doing nothing unless there is some other code to call it.

Notice that we have omitted the Public / Private keywords and that there are no parentheses after the procedure name since it does not take any arguments. Also notice that the code inside of the procedure is indented; this is not required, but is a common convention since it makes the code easier to read. The indentation suggests the hierarchical relationship between the procedure and the code within it.

Here is a similar procedure that takes one argument (PROCEDURE_ARGUMENT.VBS ).



Option Explicit




GreetUser "Bill"




Sub GreetUser(strUserName)




MsgBox "Hello, " & strUserName &_




". Welcome to our script."




End Sub


Notice how the addition of the strUserName argument, along with an adjustment to the procedure name, allows us to make the procedure more generic, which in turn makes it more reusable.

Function Syntax

The syntax for a function is identical to that of a procedure, except that you change the keyword Sub to the keyword Function .

[PublicPrivate] Function

Name

([Argument1],[ArgumentN])
    
    [code inside the function]
End Function

The rules for naming, Public / Private , and the declaration of arguments are the same as for procedures. As we've said, the distinction between a function and a procedure is that a function returns a value. Here is an example that illustrates the syntax for a function and how the code within a function sets the return value for the function ( FUNCTION_SIMPLE.VBS ).



Option Explicit




Dim lngFirst




Dim lngSecond




lngFirst = 10




lngSecond = 20




MsgBox "The sum is: "& AddNumbers(lngFirst, lngSecond)




Function AddNumbers(lngFirstNumber, lngSecondNumber)




AddNumbers = lngFirstNumber + lngSecondNumber




End Function


AddNumbers may not be the most useful function in the world, but it serves well to illustrate a few things. First, notice that this function has two arguments, lngFirstNumber and lngSecondNumber . The arguments are used inside of the function. Second, notice that the way the return value is specified is by referring to the name of the function within the code of the function. That's what is going on in this line.

AddNumbers = lngFirstNumber + lngSecondNumber

It's as if there is a nondeclared variable inside of the function that has the same exact name as the function itself. To set the return value of the function, you set the value of this invisible variable. You can do this from anywhere inside the function, and you can change the return value of the function repeatedly just as you can with a normal variable. If you set the return value more than once inside the function, the last such line of code to execute before exiting from the function is the one that sets the value.

Let's join together a procedure and a function in order to demonstrate how functions and procedures can be used together in a nested fashion ( PROCEDURE_FUNCTION_NESTED.VBS ).



Option Explicit




GreetUser




Sub GreetUser




MsgBox "Hello, "& GetUserName & _




". Welcome to our script."




End Sub




Function GetUserName




GetUserName = InputBox("Please enter your name.")




End Function


Notice how the GreetUser procedure calls the GetUserName function. Functions and procedures can work together in this way, which is how programs are built. Break your code up into specific modular building blocks of procedures and functions that do very specific things and then string the building blocks together in a logical manner.

This example brings up a good opportunity to introduce an important principle that we will discuss in more detail in the 'Design Strategies for Procedures and Functions' section of this chapter. There is a flaw in our nested procedure-function design. The GreetUser procedure has an unnecessary coupling to the GetUserName function. What this means is that GreetUser ' knows about' and depends on the GetUserName function. It depends on it because it makes a call to it; GreetUser won't know whom to greet if it does not ask GetUserName for a name.

Some amount of 'coupling' amongst code modules is necessary and good, but coupling is also something that you want to avoid if you don't need it. The more couplings in your program, the more complex it is. Some complexity is inevitable, but you want to reduce complexity as much as possible. When functions and procedures are coupled together in a haphazard manner, you get what is famously known as 'spaghetti code'-that is, code in which it is impossible to trace the logic because the logic twists and turns in a seemingly random pattern.

Here's a different version of the same script that eliminates the unnecessary coupling.



Option Explicit




GreetUser GetUserName




Sub GreetUser(strUserName)




MsgBox "Hello, " & strUserName & _




". Welcome to our script."




End Sub




Function GetUserName




GetUserName = InputBox("Please enter your name.")




End Function


The logic of the program is the same, but now we have decoupled GreetUser and GetUserName . We did this by restoring the strUserName argument to GreetUser and instead using the code at the top of the script to put the two functions together without either function 'knowing about' the other. Here is the interesting line of code in this script.

GreetUser GetUserName

The return value from the GetUserName function is fed as the strUserName argument of the GreetUser function.

One final note about function syntax: programmers familiar with other languages may have noticed that there is no way to declare the data type of a function's return value. This makes sense if you remember that VBScript supports only one data type-the Variant . Since all variables are Variant s, there is no need for syntax that specifies the data type of a function.

One way that many VBScript programmers choose to help with code clarity in this regard is to use the same Hungarian type prefixes in front of their function names as they do for their variable names. For example, GetUserName could be renamed strGetUserName . However, if you choose to follow this convention, it is extra important to name your variables and functions so that they are easy to tell apart. Using the verb-noun convention for function names helps, such that it becomes obvious that strUserName is a variable and strGetUserName is a function.

Calling Procedures and Functions

In the preceding examples of procedures and functions, you may have noticed some differences in the syntax for calling a procedure as opposed to a function. There are indeed differences, and the VBScript compiler is very particular about them.

Here is one way to call a procedure.



GreetUser "Bill"


Here is another.



Call GreetUser("Bill")


These two conventions are functionally equivalent, and whichever you choose is largely a matter of taste. Some would argue that the second convention (using the Call keyword) is more clear, but both conventions are equally common and Visual Basic and VBScript programmers over time become very accustomed to one or the other.

The next example, however, is not legal for calling a procedure and will produce a compilation error.



GreetUser("Bill")


Likewise, this example is also illegal for calling a procedure.



Call GreetUser "Bill"


When calling a procedure (as opposed to a function), if you choose not to use the Call keyword, then you cannot use parentheses around the argument value you are passing to the procedure. Conversely, if you do wish to use the Call keyword, then the parentheses are required.

The rules for calling functions are a bit different. If you want to receive the return value from a function, then you must not use the Call keyword and you must use parentheses around the argument list, like so:



lngSum = AddNumbers(10,20)


This syntax is illegal because it omits the parentheses.



lngSum = AddNumbers 10,20


And this is illegal as well because you cannot use the Call keyword when receiving the return value.



lngSum = Call AddNumbers(10,20)


You can, however, use the Call keyword if you do not wish to receive the return value of the function, but you have to use the parentheses.



Call AddNumbers(10,20)


You could also omit the Call keyword and still ignore the return value, but you must omit the parentheses in that case.



AddNumbers 10,20


This begs the question: why would you ever want to call a function if you did not want the return value? The code in the preceding two examples might compile, but it looks awfully silly. Generally speaking, functions are functions because they return values and we call functions because we want the values they return.

However, there are cases where it makes sense to ignore the return value and call a function as if it were a procedure. The way we have been using MsgBox is a good example of this. MsgBox can be used as either a procedure or a function, depending on why you need it. MsgBox has dual purpose. It can just display a message for you, which is how we've been using it, or you can use it as a function to find out which button a user clicked on the dialog box. Here is a script that illustrates the two ways of using MsgBox ( MSGBOX_DUAL.VBS ).



Option Explicit




Dim lngResponse




Dim strUserName




lngResponse = MsgBox("Would you like a greeting?", vbYesNo)




If lngResponse = vbYes Then




strUserName = GetUserName




GreetUser strUserName




End If




Sub GreetUser(strUserName)




MsgBox "Hello, " & strUserName & _




". Welcome to our script."




End Sub




Function GetUserName




GetUserName = InputBox("Please enter your name.")




End Function


In this line of code we are using MsgBox as a function.

lngResponse = MsgBox("Would you like a greeting?", vbYesNo)

MsgBox has some optional arguments, one of which is the second argument that allows you to specify if you want the dialog box to offer more buttons than just the OK button. This use of the MsgBox function produces the dialog box shown in Figure 4-1.

If the user clicks the Yes button, the MsgBox function will return a certain value (defined as vbYes in this example). If the user clicked Yes , then the familiar GreetUser procedure will eventually be called, in which you can see how we can call MsgBox as a procedure instead of as a function.


Figure 4-1

Note  

vbYesNo and vbYes from the example are built-in VBScript 'named constants,' which are like variables with fixed, unchangeable values. (We will cover named constants later in this chapter.)

Optional Arguments

As we just saw with the MsgBox function in the previous section, procedures and functions can have optional arguments. If an argument is optional, then you don't have to pass anything to it. Generally, an optional argument will have a default value if you don't pass anything. Optional arguments will always appear at the end of the argument list; mandatory arguments must come first, followed by any optional arguments.

However, the procedures and functions you write yourself using VBScript cannot have optional arguments. The built-in VBScript procedures you call (such as MsgBox ) can have optional arguments, but your own VBScript procedures cannot. If you need to, you can get around this by defining mandatory arguments and interpreting a certain value (such as Null) to indicate that the caller wants that argument to be ignored. This kind of 'fake' optional argument can help you sometimes in a bind, but this technique is generally discouraged.

Exiting a Procedure or Function

A procedure or function will exit naturally when the last line of code inside of it is done executing. However, sometimes you want to terminate a procedure sooner than that. In this case, you can use either of the statements Exit Sub (for procedures) or Exit Function (for functions). The code will stop executing wherever the Exit statement appears and the flow of the code will return to the caller.

With the simple functions we have been using as examples, there has not been an obvious place where you would want to use Exit Sub or Exit Function . Usually these statements are used inside of more complex code in situations where you have reached a logical stopping point or dead end in the logic. That said, many programmers discourage the use of these statements in favor of using a code structure that does not require them. Take this code, for example ( EXIT_SUB.VBS ).



Option Explicit




GreetUser InputBox("Please enter your name.")




Sub GreetUser(strUserName)




If IsNumeric(strUserName) or IsDate(strUserName) Then




MsgBox "That is not a legal name."




Exit Sub




End If




MsgBox "Hello, "& strUserName & _




". Welcome to our script."




End Sub


Notice the Exit Sub in the GreetUser procedure. We have added some logic that tests to make sure the name is not a number or date, and if it is, we inform the user and use Exit Sub to terminate the procedure. However, many programmers would argue that there is a better way to do this that does not require the use of Exit Sub , as in this example ( EXIT_SUB_NOT_NEEDED.VBS ).



Option Explicit




GreetUser InputBox("Please enter your name.")




Sub GreetUser(strUserName)




If IsNumeric(strUserName) or IsDate(strUserName) Then




MsgBox "That is not a legal name."




Else




MsgBox "Hello, "& strUserName & _




". Welcome to our script."




End If




End Sub


Notice that instead of using Exit Sub we have used an Else clause. The principle at work here is to design the procedure to have only one exit point, that being the implicit exit point at the end of the procedure. By definition, procedure or function with an Exit statement has more than one exit point, which some programmers would argue is poor design. The logic behind this principle is that procedures with multiple exit points are more prone to bugs and harder to understand.