VBScript Programmer's Reference
Authors: Kingsley-Hughes A. Kingsley-Hughes K Read D.
Published year: 2003
Pages: 45-46/242
Buy this book on amazon.com >>

Variable Lifetime

A variable's lifetime is closely tied to its scope. Lifetime, as the term suggests, refers to the time that a variable is in memory and available for use. A variable with procedure-level scope is only alive as long as that procedure is executing. A variable with script-level scope is alive as long as the script is running. A variable with class-level scope is alive only while some other code is using an object based on that class.

By limiting a variable's scope, you also limit its lifetime. Here is an important principle to keep in mind: you should limit a variable's lifetime, and therefore its scope, as much as you can. Since a variable takes up memory, and therefore operating system and script engine resources, you should keep it alive only as long as you need it.

By declaring a variable within the procedure in which it will be used, you keep the variable from taking up resources when the procedure in which it resides is not being executed. If you had a script file that contained ten procedures and functions, and you declared all of your variables at the script level, you would not only create some pretty confusing code, but also cause your script to take up more resources than necessary.

Really, though, resource consumption is not the most important reason for limiting variable scope. The most important reason is that limiting scope decreases the chance for programming errors and makes code more understandable and maintainable . If you have a script with several procedures and functions, and all of your variables are declared at the script level so that any of those procedures and functions can change the variables, then you've created a situation in which any code can be changing any variable at any time, and this can become very difficult for a programmer to keep up with.

It is best to design your scripts and classes so that you have the fewest possible number of variables that are available to all of the procedures and functions in your script or class. Instead, make use of local variables and procedure parameters as much as possible so that each procedure only has visibility to the data that it absolutely needs.

Let's look at an example that illustrates variable scope and lifetime in a non-class-based script ( SCOPE.VBS ).



Option Explicit




Private datToday




datToday = Date




MsgBox "Tommorrow's date will be "& AddOneDay(datToday) & "."




Function AddOneDay(datAny)








Dim datResult




datResult = DateAdd("d", 1, datAny)




AddOneDay = datResult




End Function


This script contains a function called AddOneDay() . The variable datResult is declared with Dim inside the function and has procedure-level scope, which means that it is not available to any of the code outside of the function. The variable datToday is declared with Private and has script-level scope. The variable datResult will be active only while the AddOneDay() function is executing, whereas the datToday variable will be active for the entire lifetime of the script.



Design Strategies for Scripts and Procedures

Take another look at our last example ( SCOPE.VBS ). Note that we could have instead designed this script this way ( SCOPE_BAD_DESIGN.VBS ).



Option Explicit




Private datToday




datToday = Date




AddOneDay




MsgBox "Tommorrow's date will be " & datToday & "."




Sub AddOneDay()




datToday = DateAdd("d", 1, datToday)




End Sub


This code is 100% legal and valid, and the ultimate result is the same as the original. Since datToday has script-level scope, it is available to the code inside of AddOneDay (which we've now changed from a function to a procedure), we simply designed AddOneDay to change datToday directly. It does work, but this kind of technique creates some problems.

First, we have lost the reusability of the AddOneDay function. Now AddOneDay is 'tightly coupled ' to the script-level variable datToday . If we want to copy AddOneDay and paste it into another script so we can reuse it, we've made our job a whole lot more difficult. When it was a stand-alone function with no knowledge of any data or code outside of itself, it was totally portable, generic, and reusable.

Second, while this simple situation in this simple script might seem innocent enough, try to imagine a more complex script with a couple dozen script-level variables. Imagine also a couple dozen procedures (no functions), and all of the procedures make changes to the script-level variables. Imagine these procedures calling each other and all of the script-level variables changing values rapidly . In imagining this script, hopefully you can also imagine that the logic of this script would be very chaotic and difficult to keep track of. There would be a lot of strange , hard to find bugs . Fixing one bug could easily create three others.

Keep in mind that we are not suggesting that you not use script-level variables or that you never change their values. It's all in how you go about doing it. The strategy you want to employ is to limit the number of places in your script that directly read and change script-level variables.

A great way to accomplish this is to think of the code at the top of your script file as the 'main' code, the code that controls the overall logic of the script. Lets call this code the puppet master. Then think of the procedures, functions, and classes inside of your script as puppets that have very specific jobs to do, but only do them when asked to by the puppet master code. Furthermore, the puppets are also kind of dumb. They don't know the big picture. The puppet master code keeps them in the dark by only giving them the information (by way of their arguments) they absolutely need in order to do their respective jobs. The puppet master forbids each puppet from changing any data outside of its very specific scope.

Some puppets are smarter than others, and the smarter puppets can enlist the help of the other puppets when necessary. In other words, sometimes one of the puppets might have a job that's somewhat complex, and it needs to call on one or more other puppets. At the lowest level you have very dumb puppets that do one very specific thing and don't get help from any other puppets.

Let's bring this back down to earth with an example, followed by some general principles. First, take a look at this script ( SENTENCE_NO_PROCS.VBS ).



Option Explicit




Dim strSentence




Dim strVerb




Dim strNoun




'Start the sentence




strSentence = "The "




'Get a noun from the user




strNoun = InputBox("Please enter a noun (person, " & _




"place, or thing).")




'Add the noun to the sentence




strSentence = strSentence & Trim(strNoun) & " "




'Get a verb from the user




strVerb = InputBox("Please enter a past tense verb.")




'Add the verb to the sentence




strSentence = strSentence & Trim(strVerb)




'Finish the sentence




strSentence = strSentence & "."




'Display the sentence




MsgBox strSentence


This essentially useless script goes through a series of steps to build a simple sentence based on input from the user. All of the code is in a single block with no procedures or functions, and the code shares access to script-level variables. Here is the same procedure broken into procedures and functions along the lines of our puppet master and puppets metaphor ( SENTENCE_WITH_PROCS.VBS ).



Option Explicit




Dim strSentence




strSentence = GetThe




strSentence = strSentence & GetNoun & " "




strSentence = strSentence & GetVerb




strSentence = strSentence & GetPeriod




DisplayMessage strSentence




Function GetThe




GetThe = "The "




End Function




Function GetNoun




GetNoun = Trim(InputBox("Please enter a noun (person, place, or thing)."))




End Function




Function GetVerb




GetVerb = Trim(InputBox("Please enter a past tense verb."))




End Function




Function GetPeriod




GetPeriod = "."




End Function




Sub DisplayMessage(strAny)




MsgBox strAny




End Sub


In this version we have a single script-level variable with a block of code at the top that coordinates the logic leading to the goal of the script: to build a sentence and display it to the user. The code at the top of the script uses a series of functions and one procedure to do the real work. Each function and procedure has a very specific job and makes no use of any script-level data. All of the functions and procedures are 'dumb' in that they do not have any 'knowledge' of the big picture. This makes them less error prone, easier to understand, and more reusable.

Another benefit is that you do not have to read the whole script in order to understand what's going on in this script. All you have to do is read these five lines and you have the entire big picture.

strSentence = GetThe
strSentence = strSentence & GetNoun & " "
strSentence = strSentence & GetVerb
strSentence = strSentence & GetPeriod
DisplayMessage strSentence

If, after getting the big picture, you want to dive into the specific details of how a particular step is accomplished, you know exactly where in the script to look. Even though this is a silly example not rooted in the real world, hopefully it illustrates the technique of strategically modularizing your scripts.

Here are some general principles to aid you in your script designs:

  • Simple script files that perform one specific job with a limited amount of code can be written as a single block of code without any procedures or functions.

  • As script files become more complex, look for ways to break the logic down into subparts using procedures, functions, and/or classes.

  • As you break the logic into subparts, keep the coordinating code at the top of the script file.

  • Design each procedure and function so that it has a very specific job and so that it does only that job. Give the procedure a good descriptive name that indicates what job it does.

  • Design each procedure and function so that it does not need to have any 'knowledge' of the script file's 'big picture.' In other words, individual procedures and functions should be 'dumb,' only knowing how to do their specific job.

  • As much as possible, keep the procedures and functions from reading from or writing to script-level variables. When procedures and functions need access to some data that is stored in a script-level variable, include it as an argument rather than accessing the script-level variable directly.

  • If the value of a script-level variable needs to be changed, use the coordinating code at the top of the script file to make the change.


VBScript Programmer's Reference
Authors: Kingsley-Hughes A. Kingsley-Hughes K Read D.
Published year: 2003
Pages: 45-46/242
Buy this book on amazon.com >>

Similar books on Amazon