Accessibility
 
What's So Great About User Defined Functions?

By Tim Buntel
Product Manager
Macromedia, Inc.

At the Washington D.C. ColdFusion Developer's Conference, the opening day keynote presentation featured a Macromedia ColdFusion Server 5 preview. ColdFusion Product Evangelist Ben Forta explained to the audience how many of version 5's features were inspired directly from feedback from developers. "Probably the most requested feature," he began, "Well, let me just show you…" The brief example that followed received a rousing ovation from the audience. What was this applause-earning most-requested feature? User defined functions (also known as Custom Functions).

An Introduction

What, exactly, is a function? In programming, a function is a named section of the program that performs a specific task. When called, a function performs its task, the program resumes, and the function usually returns a value.

In CFML, we use functions all the time. There are string functions such as Len, Find, and Replace. There are display functions like DateFormat and DollarFormat, and there are array functions including ArraySort, ArrayLen, and IsArray. CFML, in fact, is comprised of more functions than tags!

Even with all of these native functions in CFML, though, there are always even more uses for functions that come up in the course of developing an application. No language could possibly provide native functions for them all. That's why many languages, such as JavaScript, give developers the ability to create their own functions. And now, so does CFML.

User defined functions can even be stored in libraries and reused again and again in different applications - just like native CFML functions. In fact, there's already an open-source project underway to create topical UDF libraries for CFML developers - the Common Function Library Project (CFLP) at http://www.cflib.org/.

For Example?

What kind of programming task makes for a good user defined function? Think of things that you do frequently within a page or application that involve some sort of input and some sort of output. There are formatting functions to remove certain characters from strings, validation functions that check that data follow a certain format such as E-mail addresses or social security numbers, and math and scientific functions, as well as many others.

How They Work

User defined functions are defined within CFSCRIPT blocks. This definition needs to be either in the same template as a call to it (even if it is after the call - for best practices, though, try to keep definitions together above the call) or in a template which was included (either with cfinclude or through the application framework) before the call. You can then use the function anywhere that you use a ColdFusion expression, such as in tag attributes, between # signs in output, and in CFSCRIPT code.

The definition of a user defined function uses regular CFSCRIPT code plus two new statements: var and return. Var (used as Var variableName = InitialValue;) declares a variable local to the function. Return (used as Return expression;) returns the specified value to the processing page and terminates processing in the function. The syntax for defining the function itself is as follows:

function functionName( [paramName1[, paramname2...]] ) { 
CFScript Statements 
} 
 
 Here's a simple example:


function Greetings(aName) {
	var aGreeting = "Hello, " & aName;  
	return aGreeting;
}


#Greetings("Tim")#

When browsed, this polite little user defined function says, "Hello, Tim!" Certainly not a terribly useful UDF, but you see the basic structure - declare the function with its name and arguments, use CFSCRIPT to do something, then return a value.

Here's something a bit more practical - a Fahrenheit to Celsius conversion function:


function TempConvert(ATemp, ItsScale){
if (not IsNumeric(ATemp)) return "NAN";

if (UCase(ItsScale) eq "F")
	// temp given in Fahrenheit.  Convert to Celsius
	degs = (ATemp - 32.0) * (

/9.0);
else if (UCase(ItsScale) eq "C")	
	// temp given in Celsius.  Convert to Fahrenheit
	degs = (ATemp * 9.0/5.0) + 32;
else
	degs = "Not a valid scale";
;
return degs;
}


50 degrees Fahrenheit is #TempConvert("50","F")# degrees Celsius.

Which, of course, prints, "50 degrees Fahrenheit is 10 degrees Celsius." How? Two arguments are passed to the function: a temperature and the scale that it is in. The temperature is checked to make sure it's a number (the value "NAN" is returned and processing ends if it is not). Then the calculation is processed based on the scale being "F" or "C." If the scale given is neither "F" nor "C," the message "Not a valid scale" is returned.

When Should I Use UDFs Instead of Custom Tags?

This is all fine, but isn't the function of letting you write code once and use it many times in your pages the job of a custom tag? Both techniques can help you accomplish many of the same tasks, but each are subtly better suited to certain types of problems.

One important differentiation is that user defined functions - since they are written in CFSCRIPT - do not include access to any native CFML tag functionality. Only the custom tag architecture will allow you to use CFQUERY, CFHTTP, CFMAIL, or any other CFML tags.

On the other hand, only user defined functions provide the convenience of return values. Custom tags can create values (as Caller.VariableName) that are accessible to the calling template after their execution, but with UDFs the return value is the primary goal of the function. For example, the above Celsius/Fahrenheit conversion function as a custom tag may look something like this:

In a file called TempConvert.cfm:

<cfif NOT IsNumeric(Attributes.ATemp)> <cfset degs="NAN"> <cfelse> <cfif UCase(Attributes.scale) eq"C"> <!--- temp given in Celsius. Convert to Fahrenheit ---> <cfset degs=(Attributes.ATemp * 9.0/5.0) + 32> <cfelseif UCase(Attributes.scale) eq"F"> <!--- temp given in Fahrenheit. Convert to Celsius ---> <cfset degs=(Attributes.ATemp - 32.0) * (5.0/9.0)> > <cfelse> <cfset degs="Not a valid Scale"> </cfif> </cfif> <cfset Caller.degs=degs>

Which would then be used in a page to do what was demonstrated with the UDF as follows:

<cf_TempConvert scale="f" aTemp="50"> 50 degrees Fahrenheit is <cfoutput>#degs#</cfoutput> degrees Celsius.

In this case, the custom tag style requires the processing of the task (as ) be separate from the outputting of the result. Whereas in the UDF style, the processing and the display of the result were one and the same:

50 degrees Fahrenheit is <cfoutput>#TempConvert("50","F")#</cfoutput> degrees Celsius.

Finally, performance may be worth some consideration when deciding to use UDFs or custom tags. If a function is to be performed multiple times within one template, a UDF would most likely out-perform the custom tag. This is due to the fact that processing does not have to leave the template every time a UDF is executed. With the custom tag, it goes out to the tag itself each time processing of the task is required.

Conclusion

ColdFusion Server 5 has many features aimed at increasing developer productivity - do more, more easily. For those of you who have long hoped for user defined functions in CFML, here you go! For those of you who may be new to the idea of UDF's, I encourage you to play with some code and try them out. You will be able to do more, more easily with UDF's - as well as with the new features in ColdFusion Server 5. And keep watching for future articles where some of those other new features will be explored, too.