Paramuments: Making Functions more Functional

Introduction

We’re going to revisit the coin slot and see how we can use it to let functions take variable inputs to produce more dynamic outputs.

Scope of Application

Today’s post was drafted using Microsoft Word 2013 running on a Windows 8.1 machine. But what I’ll cover applies at least as far back as Word 2007 and Windows XP and the equivalent versions of Word for the Mac. If you don’t have Word, you can get a trial copy from Microsoft’s website.

A Quick Review of our singleDouble macro

In my Cheater’s Code trilogy, I showed you a macro that turned out something like this (edited for focus):

Sub singleDouble()
'
' singleDouble Macro
'
'
Selection.Find.ClearFormatting
Selection.Find.Replacement.ClearFormatting
With Selection.Find
.Text = ".*<"
.Replacement.Text = ".  "
.MatchWildCards = True
.MatchCase = True
End With
Selection.Find.Execute Replace:=wdReplaceAll
End Sub

 

We used that to replace a period followed by anything leading up to the beginning of a word (“.*<“), and replace it with a period followed by two spaces (“.  “)–or, in other words, to find a period followed by any number of spaces, and replace it with a period followed by two spaces.

Then I pointed out that we’d have to correct for things like Dr., Mrs., etc. showing up elsewhere in the text by running a very similar macro:


Sub correctSingleDouble()
'
' correctSingleDouble Macro
'
'
Selection.Find.ClearFormatting
Selection.Find.Replacement.ClearFormatting
With Selection.Find
.Text = "([DIJMNOPRS][cdnoprst]{1,3})(.  )(<?)"
.Replacement.Text = "\1. \3"
.MatchWildcards = True
.MatchCase = True
End With
Selection.Find.Execute Replace:=wdReplaceAll
End Sub

 Well, you probably noticed that with the exception of the Text and Replacement Text, the code of these two macros is exactly the same. Now imagine that you have 10 different find and replace searches to perform on each document you work on. Repeating this one pattern 10 times would produce over 100 lines of code–but the only thing changing are the find and replace values. Sure, it’s easy to copy and paste all that, but it’s not really efficient. For that reason alone, we should look for a way to change the values without repeating the rest of the code. We’re looking for reusability.

Parameters

This brings me back to the coin slot. In case you don’t remember (or skipped my Cheater’s Code trilogy), I referred to those parentheses after the macro name as a coin slot and compared it to those machines at the mall that smoosh a penny. The machine has a place for you to pass something in, and when you do that, it sets to work on what you’ve given it. The machine doesn’t care what year the quarters were minted in, whether the penny is a wheat penny, or if you also have six nickels in your pocket. The machine will not, however, accept forms of currency it doesn’t expect. You can’t put an equivalent amount of Yen into the machine and make it work. It knows the size and the shape of the input it wants. And that’s what we would call a parameter in programming parlance.

Parameters basically allow you to do two things:

  • Enable a function to accept input
  • Describe the type of input the function will accept

In our macro, we want to pass in a Find value, and a Replace value. That means we’ll need two parameters. We create them by giving them names and identifying their types in the parentheses after the macro name–carving out the coin slot. Let’s create a new macro called “findReplace” and set up some parameters:

Sub findReplace(findThis As String, replaceWithThis As String)

End Sub

Different programming languages can handle this slightly differently, but in VBA you provide a name (something you make up), followed by As [Type]. If you don’t quite understand what I mean by “type,” I’ll be covering that in another post. Don’t worry about it too much now. You know that this particular macro is working with strings, so we need our parameters to be strings.

Let’s go ahead and fill in the rest of the macro:

Sub findReplace(findThis As String, replaceWithThis As String)

Selection.Find.ClearFormatting
Selection.Find.Replacement.ClearFormatting
With Selection.Find
.Text = findThis
.Replacement.Text = replaceWithThis
.MatchWildcards = True
.MatchCase = True
End With
Selection.Find.Execute Replace:=wdReplaceAll

End Sub

Notice that now the Text and Replacement Text now point to the names of our parameters. Going back to our penny smoosher comparison, this is like saying, “Take a quarter and a penny. If it’s a nickel or a dime, don’t accept it. Also, it doesn’t have to be any particular quarter or particular penny. It just needs to be a quarter and a penny.”

Now you can call this macro and pass in any two strings.

Arguments

When I was starting out, I found the difference between parameters and arguments to be a little confusing. Basically, it’s this: when you carve out a coin slot, you create parameters. The slot for the penny and the quarter are the parameters. The quarter and the penny–the objects actually going into the coin slots, are the arguments. Parameters define the input allowed, arguments are the input. (If anyone knows why we use the term arguments, I’d love to be able to answer that trivia question.)

Now that we have findReplace, we don’t need all that code in singleDouble. In fact, we really only need one line of code there:

Sub singleDouble

Call findReplace(".*<",".  ")

End Sub

 Simple, right? findReplace has a place for two strings, and we’re giving it two strings. It will use them as the Find and Replace values, respectively. We passed in the values we want to use as arguments. Hopefully now you see where the title of the post comes from.

We could make the same edit to correctSingleDouble, but in this case I’m pretty sure that whenever we replace one space after a period with two spaces after a period, we’ll want to correct for abbreviations. Since both operations always need to be performed, we can just stick them in the same macro. Remember, that would have originally meant 20 lines of code. Now that we have the findReplace abstraction, it’s just two lines:

Sub singleDouble

Call findReplace(".*<",".  ")
Call findReplace("([DIJMNOPRS][cdnoprst]{1,3})(.  )(<?)","\1.  \3")

End Sub

Now when we find ourselves in a situation where we need to run the same function on 10 different sets of strings, we don’t have to copy and paste 10 lines of code over and over. We just generate one new line of code for each new find and replace operation. That will make it easier to read, easier to edit, and boost performance.

Prompt

If we had 10 find and replace options to perform, how could we make this even more efficient?

Love and kisses,

Tyler

Advertisements

2 thoughts on “Paramuments: Making Functions more Functional

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s