Anda di halaman 1dari 8

Chapter 12 - Good Programming Techniques

CHAPTER 12 - GOOD PROGRAMMING TECHNIQUES

This chapter shows how to use some of the more advanced programming techniques in VBA,
such as passing arguments by reference and value, using optional arguments and writing
recursive programs.

12.1 Passing Arguments by Reference and Value

By default in VBA arguments are passed by reference (ByRef) rather than by value (ByVal).
What does this mean?

An Example of Passing by Reference

The example code below calculates the factorial of a number (eg 4! = 4 * 3 * 2 * 1 = 24).
Running the macro for an input of 4 should give the following dialog boxes:

Typing in this input would give the following message:

Here is a macro to do this – it’s not particularly well written, but it shows the principles:

This line of code calls the


IncludeNextNumber subroutine,
passing in the value of CurrentAnswer.
After running this routine, the value of
CurrentAnswer is also changed in the
main CreateFactorialByRef routine –
otherwise this macro wouldn’t work.

This shows that the CurrentAnswer


argument is being passed by reference
(this is the default anyway, and so this
could be omitted). What this means is
that any changes to CurrentFactorial in
this subroutine will get passed back into
the main routine as changes to
CurrentAnswer.

© Copyright 2010 Page 99


Chapter 12 - Good Programming Techniques

An Example of Passing Arguments by Value

The following subroutine would achieve exactly the same results, but has been written to pass
arguments by value:

After calculating the factorial, we


display it:

Because of the way this is written,


it is vital that the CreateFactorial
function doesn’t change the value
of n during its calculations.

Because this function definitely


does change the value of n
(known within this function by its
alias TestNumber), we must pass
the argument by value to avoid
changes being passed back to the
calling routine.

VB.NET programmers will be used to arguments being passed by value


Wise Owl’s
(not reference) by default, and should take care!
Hint

© Copyright 2010 Page 100


Chapter 12 - Good Programming Techniques

Public Variables vs. Passing by Reference

It is a source of lively debate in the Wise Owl office whether it is better to pass arguments by
reference or to use public variables. The following two routines both calculate the factorial of an
input number:

This is the answer we’ve seen already


– the value CurrentAnswer is
changed by the IncludeNextNumber
routine, and this change is passed back
to the main calling routine.

Here we create a public


variable (for this module)
to hold the current answer.

This subroutine doesn’t need to pass in


the value of CurrentAnswer …

… as it will be visible in
the subroutine also.

So which routine is better?

♦ Purist programmers will argue that you should avoid public variables, as you can never
be certain that their value won’t be inadvertently changed by other routines – all
common values should be passed into subroutines by reference.

♦ Realists will argue that using public variables creates shorter code which is easier to
understand (there are less long lists of arguments to interpret).

You should decide into which camp you fall!

© Copyright 2010 Page 101


Chapter 12 - Good Programming Techniques

12.2 Recursive Programming

One of the most powerful programming techniques is to write macros which call themselves.

The dictionary definition helps here:


Wise Owl’s
Recursion (n.) – See under “recursion”
Hint

A typical example of recursive programming is to list out all of the members of a tree. Consider
the following spreadsheet of employees:

This line shows (for example) that employee


number 1 is Simon Templar, and he reports to
employee number 6 (Alastair Campbell).

Change a person’s name here, and Excel will automatically


display all of their subordinates in the debug window:

The great benefit of storing a hierarchical relationship like this is that it


Wise Owl’s makes the data take up much less space – each employee record just
Hint
stores their id number, their name and their parent’s id number.

To solve this problem we need to list out for each employee chosen:

♦ The names of all their immediate subordinates.


♦ For each of these subordinates, the names of their subordinates.
♦ For each of these “grandchildren”, the names of their children

And so on for as many levels as it takes! Experienced programmers will immediately recognise
that we can write one function to list out an employee’s immediate subordinates, and call this
recursively.

© Copyright 2010 Page 102


Chapter 12 - Good Programming Techniques

Our Example Routine


Our macro is assigned to the Change
The following routine would solve our problem! event for the worksheet – so when a
user chooses a different person, the
macro will fire.

Only list subordinates if we’ve changed


cell B16:

For the example of Alastair Campbell


shown above, PersonCell would now refer
to B7 (the cell containing his name).

This will call the subroutine to list out the


subordinates of Alastair Campbell, passing
in his id number 6 as an a argument.

We loop over all the parent id cells (shown


shaded below), finding any which match
this person (ie finding this person’s
immediate subordinates):

Write this person’s name to the immediate


window, indented according to hierarchy.

For Simon Templar (for example) this


would list out his name, and then pass his
employee id (in his case, 1) to the same
routine to then list out all his subordinates
(and, recursively, their subordinates too).

© Copyright 2010 Page 103


Chapter 12 - Good Programming Techniques

12.3 Optional Arguments

Optional arguments are a powerful technique – they allow you to make one routine do two
different things.

Optional arguments are especially useful when you want to tack on an


Wise Owl’s argument to one call to an existing subroutine without having to change
Hint all the other calls.

As an example, consider the following straightforward code to add a person to a table in


Microsoft Access:

After adding someone, their name will


appear in the Owner table:

Suppose that we now add another argument to the Owner table stating whether an owner is a
celebrity or not:

Our new argument.

To do this, we can amend our subroutine call as shown overleaf.

© Copyright 2010 Page 104


Chapter 12 - Good Programming Techniques

We can solve our problem without having to rewrite every call to AddOwner by making the
argument optional:

Here we have an optional 3rd


argument, specifying whether or
not the new owner is a celebrity.
If this argument isn’t set, it will
default to False, which is
probably sensible.

The new field


is set here.

The following code would call this routine twice – once setting the 3rd argument, once not:

This will compile even though the


number of arguments is different for
the two subroutine calls. Marvin
McMillan will not be a celebrity.

Optional arguments must be the last ones in the list, which is why the
following subroutine declaration appears in red as invalid syntax:
Wise Owl’s
Hint

© Copyright 2010 Page 105


Chapter 12 - Good Programming Techniques

Using ParamArray to Pass Arrays of Optional Arguments

Dedicated programmers might like to look at an alternative way to pass arrays of optional
arguments, using ParamArray. To solve the problem below, you could use 3 optional
arguments:

This subroutine calls the GetAddress function


twice to display an address – but the second call
has 4 arguments and the first one only has one.
The two messages
displayed by this
subroutine.

Ideally we would be able to pass as many additional address lines as we wanted:

You must pass one argument


to this function giving a
person’s name – thereafter
you can pass as many as you
like for the address lines.

For each additional address line


passed, add it to the address.

The ParamArray keyword can only be used under the following circumstances:

♦ It must have data type Variant (even though in the above example we know we’ll be
passing strings of text).

♦ It must be the last argument in the list, just like for Optional arguments.

♦ You can not combine it with ByRef or ByVal.

© Copyright 2010 Page 106

Anda mungkin juga menyukai