Hack 76. Shrink Your Code with Optional Arguments
"Shrink Your Code with Subroutines" [Hack #75] shows you how to reduce code by using a generic subroutine. This hack takes that concept a step further. Subroutines can take optional arguments. Calling routines are required only to supply arguments that aren't optional. The optional ones are, well, optional.
Example 8-5 shows a handful of routines and the subroutine they call.
Example 8-5. A set of routines that call a subroutine
Sub get_NY_records( ) 'get New York customers get_state_records "NY" End Sub Sub get_CT_records( ) 'get Connecticut customers get_state_records "CT" End Sub Sub get_MA_records( ) 'get Massachusetts customers get_state_records "MA", "Boston" End Sub Sub get_state_records(state As String, Optional city As String) Dim conn As ADODB.Connection Set conn = CurrentProject.Connection Dim recset As ADODB.Recordset Set recset = New ADODB.Recordset If state = "MA" Then recset.Open "Select * From Customers Where State='" & state _ & "' And City='" & city & "'", conn Else recset.Open "Select * From Customers Where State='" & state & "'", conn End If Do Until recset.EOF ''Process records here recset.MoveNext Loop recset.Close Set recset = Nothing End Sub
The subroutine takes two arguments: state, which is required, and city, which is optional. The Optional keyword is placed in front of the argument name:
Sub get_state_records(state As String, Optional city As String)
Let's assume the requirements have changed; now, any NY or CT records can be used, but for Massachusetts (MA), we need only records for which the city is Boston.
One way to accommodate this new requirement is to use subroutines: one that accepts a single state argument and one that accepts two arguments, for the state and the city. The functionality would work, but there would be more code.
However, by incorporating the city as an optional argument, you can use the single subroutine for all the states. Massachusetts records are accessed by the two arguments being passed:
get_state_records "MA", "Boston"
New York and Connecticut records are accessed with the single required state argument:
We've modified the subroutine to handle two types of queries, one with a single criterion and one that uses both criteria:
If state = "MA" Then recset.Open "Select * From Customers Where State='" & state _ & "' And City='" & city & "'", conn Else recset.Open "Select * From Customers Where State='" & state & "'", conn End If
And that's it! By just altering the existing subroutine a bit, we don't need to create a second subroutine.