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.