Code Reuse

Functions


Content Author

Emily Christiansen

 

Reviewed/Revised By

Matt Gifford

coldfumonkeh

A key principle to consider when developing your applications is to not repeat code unnecessarily. This is commonly known as the DRY principle: Don't Repeat Yourself.

Now that some of the basics of programming with ColdFusion have been covered, we can take a moment to discuss code reuse. Writing code that can be used again is an important skill for developers to master; not only does it save time, but it forces the developer to structure their code such that individual routines are isolated and labelled properly. Doing this makes the code easier to read and interpret. In this chapter, simple examples will be used; you can extrapolate from these examples and imagine the effects on a larger scale.

Let's pretend I have a ColdFusion page. The function of this page is to display a greeting. The code would look something like this:

<cfparam name = "firstName" default = "Matt">
<cfparam name = "lastName"  default = "Gifford">

<cfset fullName = firstName & " " & lastName>

<cfoutput>
    Hello, #fullName#!
</cfoutput>

This code doesn't do much; it takes the first name and last name, concatenates them to make the full name, then outputs it to the screen. What if we wanted to isolate that piece of code that makes the full name and use it over and over again throughout the system? ColdFusion offers several ways to structure your code for reuse. As the language has grown and evolved over the years, it has gone from simple inclusion of files, to making individual functions, and finally embracing object-oriented programming principles. It also offers the ability to create your own custom tags. When discussing code reuse, functions are the simplest place to start.

Functions

Functions are reusable blocks of code that have a name, may take in arguments, perform some operations on those arguments, and may return a new value. Breaking complex tasks into smaller, clearly labelled functions will also make them easier to read and comprehend. Functions can be thought of as building blocks for a program.

In ColdFusion, functions are created using the function syntax. A simple function stub would look like this:

<cfscript>
public void function myFunction(){
    // Your function content goes here
}
</cfscript>

This basic function implementation does nothing and returns nothing. Before we move on, let's take a moment to go through the available function declarations and options.

  • access This controls who can see your function. If it's public, it can be called from anywhere else in the system. If it is private, only functions within the same component can call the function. Package visibility is similar to private, but allows components that are within the same package to use those functions. Remote grants web services the ability to call that function. Components will be discussed later in the chapter.
  • returntype: This describes what type of value is returned. If the function returns nothing, this is set to void.
  • name: The name of the function. This should be short, but as descriptive as possible.

Now that the stub of the function is created, it's time to make it do something. Let's say we have the name of a person stored in our database. We want to display the person's first and last name in the interface, but their name is stored in two different fields, first_name, and last_name.

If we already have the first and last names stored in variables, we can pass them into the function as an argument. We can tell our function which arguments to expect by setting them as arguments for the function:

<cfscript></cfscript>
public void function getFullName(
    required string firstName = '',
    required string lastName = ''
){
    // Your function content goes here
}
</cfscript>

In this example we are asking the function to require two arguments, firstName and lastName respectively. Both argument values are marked as required attributes. The type is set as a string for both, and a default value of an empty string has also been provided to make sure the function will not break if nothing is sent in. This is entirely optional.

Take note that the name of the function was changed. The name is much more descriptive of what it actually does; this is an example of refactoring, the process of refining code.

If we want to access the firstName and lastName variables, we will need to look in the arguments scope. This is one of the many scopes provided by ColdFusion. Variables in the arguments scope exist only for the function in which they are declared. You can access them by using arguments.yourVariableHere.

Let's put this to use in the function:

<cfscript>
public void function getFullName(
    required string firstName = '',
    required string lastName = ''
){
    fullName = arguments.firstName & ' ' & arguments.lastName;
}
</cfscript>

Even though the string is constructed, the fullName variable does not belong to a scope. We need to make sure that only this function can access fullName, so we will var scope it like so:

var fullName = arguments.firstName & ' ' & arguments.lastName;

Now that the new variable is scoped, we can now return the variable. Since the function is now returning something, we also need to change the returnType attribute in the function definition. Because we are only returning a string, we will just set it to string. Functions can return pretty much anything you want them to, including structs and objects.

In the end, the function ends up looking like this:

<cfscript>
public string function getFullName(
    string firstName = '',
    string lastName  = ''
){
    var fullName = arguments.firstName & ' ' & arguments.lastName;
    return fullName;
}
</cfscript>

The function is now built, albeit a very simple one. It is concise and clearly labelled, meaning that it is easy to read and reuse elsewhere in the system.

Now, the question is how to allow people to use it. Fortunately, calling functions in ColdFusion is only a little different than setting up any other variable. We use the cfset tag.

<cfset fullName = getFullName( firstName='Matt', lastName='Gifford' )>

When it comes to passing in arguments, there are a few ways you can do it. Above, the arguments are explicitly named going into the function. This is particularly useful for functions that have a large number of arguments, as it is far easier to keep track of what actually got passed in. Alternatively, something like this could have been done:

<cfset fullName = getFullName( 'Matt', 'Gifford' )>

This approach relies on the arguments being passed in the same order in which they are specified in the method signature above. It can get very confusing for functions with large numbers of arguments.

Another option is available if working within one function and sending the same arguments to a helper function. For example, the getFullName function could be used by another, larger function. Let's call it getGreeting:

<cfscript>
public string function getGreeting(
    string firstName = '',
    string lastName  = ''
){
    var fullName = getFullName( argumentCollection = arguments );
    // We can do more with the fullName variable here
}
</cfscript>

In the above example, argumentCollection = arguments was used to pass the same arguments from one function to another. This is very handy when passing a bunch of arguments to another function with the same argument names. This is much faster than typing out the names of each and every argument.

In order to call a function, it needs to be put somewhere. There are a number of ways to accomplish this. The simplest way is to put it in a .cfm page and call it.

<cfscript>
fullName = getFullName( firstName='Matt', lastName='Gifford' );
writeOutput( fullName );
</cfscript>

Putting the function into the very same .cfm page being used to display our greeting is not very conducive to code reuse.