Functions and
Procedures(also called subroutines) are techniques that allow scripts to be
broken down into different distinct sections. These sections can be used to aid
the clarity of the script, as scripts are by nature not the easiest document to
read. You can also use functions and procedures to increase the efficiency of a
script by putting code that is repeated in the script into one procedure and
interpret that procedure more than once.
Blocks of code can be defined inside parameters that define the beginning and end of a subroutine. The code that exists inside the subroutine can then be called and thus interpreted. By calling the subroutine more than once, the subroutine can be reused and thus saving the repetition of code in the script.
Sub1.vbs is an example of a simple subroutine that generates a line of cubes.
The subroutine construct is defined between the statements “Sub” and “End Sub”. Subroutines are named individually, and the user defines the name of the subroutine immediately after the “Sub” statement.
E.g.
This will start the subroutine construct and name the subroutine “MakeCube”. There are some rules regarding the naming of subroutines:
1> Subroutine names cannot start in numeric values.
2> Subroutine names cannot contain spaces.
It is between the “Sub name” and “End Sub” constructs that the block of code that is the subroutine is defined. Note that the code inside the subroutine cannot be interpreted unless directly specified, i.e. if a script is not told to call the subroutine and encounters the “Sub” statement during the code that follows will not be interpreted.
Subroutines are called by simply entering their name during the course of a script. For example, using the MakeCube subroutine above as an example, entering the keyword MakeCube in a script will tell the script to interpret the MakeCube subroutine. Effectively the scripting engine will move to the Sub MakeCube definition in the script and process the text until it encounters the End Sub keywords, upon which it will revert back to its original position in the script.
It is often more useful to call a subroutine by adding the statement “Call” before the name of the script.
E.g.
This makes the script easier to read because the call statement is used to directly specify the calling of a subroutine. Sometimes just using the subroutine name in a script to call the subroutine is a bit ambiguous: the “Call” command helps to remedy this.
Subroutines can be passed information to use inside the subroutine itself. These arguments are defined after the subroutine name. In the actual definition of the subroutine the arguments are enclosed in brackets.
Sub2.vbs is an example of a subroutine using arguments.
In the case of the example above, there is one argument in the MakeCube subroutine – called amount. Note that this argument does not have to be defined like a variable, even though it acting like a variable.
If the subroutine is being called without the use of the call statement then the name argument is simply described after the subroutine name,
E.g.
If the “Call” statement has been used to call the subroutine, then the arguments need to be encompassed in brackets.
E.g.
Call
MakeCube(“Echo”)
Information that is passed to subroutines via arguments can then be used to drive factors of the subroutines. In the case of the MakeCube example, the amount argument is passed into the loop .
Care needs to be taken when passing information into subroutines – in particular to the data type of the information being passed into the subroutine. Subroutines are written with specific data types in mind for the arguments. For example, with the MakeCube example, we expect to be passed an integar for the range of the loop. If we are passed a string instead of a value, the change in data type has a major effect.
E.g.
MakeCube 2.22
Will generate a series of cubes but round it up to the nearest
whole cube. Okay, it is not a fatal error but the result is not expected. If a
subroutine is passed string information into an argument, but the subroutine is
designed to be given numeric values to be used in an expression, then the
subroutine will generate an error. This will stop the script. Care has to be
taken in the form of considering the data type, and perhaps it is wise to
sometimes use some data type conversion techniques to ensure that the script
does not halt with an error if given information not consistent with its
design.
Variables can be used to
pass information into subroutines.
Sub3.vbs is an example of this.
If a variable is used in a subroutine argument, it looks at first glance that it is only the actual value of the variable that is passed into the subroutine. This is in fact untrue, as the actual variable itself is referenced throughout the subroutine by default and as such any changes that happen to the argument inside the subroutine also change the variable used to define the argument.
XTRAS:
Take sub3.vbs and using last weeks lessons on loops, see if you can generate a 3D pyramid structure using a 2 dimensional loop to generate flat areas of cubes. Once you have done that, implement the index condition from last week so that cubes are only made on the outside of the pyramid and not on the inside where we cannot see them. the complete example is in pyramid.vbs.
Sub4.vbs is an example of
this.
Notice how we define “v”
as a variable with a value of 10. A logmessage command then reports this value
to us on screen.
We then run a subroutine
called MultByTen and pass the v variable into the argument of that subroutine.
There is only one line inside the subroutine, which takes the argument, in this
case called x, and multiplies it by 10. The subroutine then exits.
A second logmessage command
then informs us that the value of v has now increased to 100. It has become
apparent that our v variable has been affected by the manipulation of the
subroutine, even though the argument is called x.
This process is called
passing arguments by reference . It means that the argument references
the variable inside the argument throughout the operation of the subroutine –
there is an indelible link between the two.
An alternate to this method
of passing information, is to instruct VBScript to simply pass a copy of the
value stored in the variable into the argument but not to pass the variable
itself. This method is known as by value . You can invoke this method by
simply adding the ByVaf statement in the definition of the subroutine
argument.
For example, change:
Sub
MultByTen( x )
To
Sub
MultByTen( ByVal x)
Running the script again
will now show no change in the value of v. It is only the value of v that is
passed into the subroutine now and not the variable v itself.
Functions
Subroutines
are great for reusing code but they have one disadvantage – they don’t pass
information back from the subroutine. Functions are another type of subroutine
that allow a block of code to be called, but they do have the ability to return
values. The majority of functions are used to return a value based upon input
arguments. The information passed back is defined by the user, and can range
from a specific numeric value through to logical statements based on the
arguments.
Load
func1.vbs
This
is an example of a simple function – in this case it takes its argument and
multiplies it by 10, passing the result back to the user.
The
block of code in a function exists between the Function and End Function statements, in a
very similar manner to the way sub … end sub operates a subroutine. In
the case of the above example, the function is named “MultByTen” and contains 1
argument called input:
Function MultByTen (input)
The
function name is very important to functions as it defines the name that the
user can reference to receive information. There are already many functions
built into VBScript – cos, sin and tan for example. We can call our user
defined function is a similar manner to using the pre–defined functions:
X = MultByTen(5)
In
the above example, we have the ability to directly link the x variable to the
function via an equality symbol. In order to achieve this, we also need to
enter an equality expression in the function code itself to define what value
we are outputting – and we do this by defining a value to a pseudo variable
named after the function name, e.g.
MultByTen = input * 10
We
can add further code inside the function itself to manipulate the output result
if desired, but we must express this output information via the pseudo
variable. The variable is automatically dimensionalised by the function, so
there is no need to declare it with a dim statement.
Examples func2.vbs and func3.vbs are further uses of simple scripts.