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:
>
Which
would then be used in a page to do what was demonstrated
with the UDF as follows:
50
degrees Fahrenheit is #degs# 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 #TempConvert("50","F")#
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.