Creating user-defined functions

Creating user-defined functions

Before you create a UDF, determine where you want to define it, and whether you want to use CFML or CFScript to create it.

Determining where to create a user-defined function

You can define a function in the following places:

  • In a ColdFusion component. If you organize your functions in ColdFusion components, you use the functions as described in Using ColdFusion components.
  • On the page where it is called. You can even define it below the place on the page where it is called, but this poor coding practice can result in confusing code.
  • On a page that you include using a  cfinclude  tag. The  cfinclude  tag must be executed before the function gets called. For example, you can define all the functions for your application's on a single page and place a  cfinclude  tag at the top of pages that use the functions.
  • On any page that places the function name in a scope common with the page on which you call the function. For more information on UDF scoping, see Specifying the scope of a function in Using UDFs effectively.
  • On the Application.cfc or Application.cfm page. For more information, see Designing and Optimizing a ColdFusion Application.
    For recommendations on selecting where you define functions, see the sections Using Application.cfm and function include files and Specifying the scope of a function in Using UDFs effectively.

About creating functions using CFScript

You use the function statement to define the function in CFScript. CFScript function definitions have the following features and limitations:

  • The function definition syntax is familiar to anyone who uses JavaScript or most programming languages.
  • CFScript is efficient for writing business logic, such as expressions and conditional operations.
  • CFScript function definitions cannot include CFML tags.
    The following is a CFScript definition for a function that returns a power of 2:
function twoPower(exponent) {
return 2^exponent;
}
</cfscript>

For more information on how to use CFScript to define a function, see Defining components and functions in CFScript.

Defining functions in CFScript

You define functions using CFScript in a similar manner defining JavaScript functions. You can define multiple functions in a single CFScript block.

Note:

For more information on using CFScript, see Extending ColdFusion Pages with CFML Scripting.

CFScript function definition syntax

A CFScript function definition has the following syntax:

{
CFScript Statements
}

The following table describes the function variables:

Function variable

Description

functionName

The name of the function. You cannot use the name of a standard ColdFusion function or any name that starts with "cf". You cannot use the same name for two different function definitions. Function names cannot include periods.

argName1...

Names of the arguments required by the function. The number of arguments passed into the function must equal or exceed the number of arguments in the parentheses at the start of the function definition. If the calling page omits any of the required arguments, ColdFusion generates a mismatched argument count error.

The body of the function definition must be in curly brackets, even if it is empty.
The following two statements are allowed only in function definitions:

Statement

Description

varvariableName = expression;

Creates and initializes a variable that is local to the function (function variable). This variable has meaning only inside the function and is not saved between calls to the function. It has precedence in the function body over any variables with the same name that exist in any other scopes. You never prefix a function variable with a scope identifier, and the name cannot include periods. The initial value of the variable is the result of evaluating the expression. The expression can be any valid ColdFusion expression, including a constant or even another UDF.All var statements must be at the top of the function declaration, before any other statements. Initialize all variables when you declare them. You cannot use the same name for a function variable and an argument.Each var statement can initialize only one variable.Use the var statement to initialize all function-only variables, including loop counters and temporary variables.

returnexpression;

Evaluates expression (which can be a variable), returns its value to the page that called the function, and exits the function. You can return any ColdFusion variable type.

A simple CFScript example

The following example function adds the two arguments and returns the result:

function Sum(a,b) {
var sum = a + b;
return sum;
}
</cfscript>

In this example, a single line declares the function variable and uses an expression to set it to the value that it returns. This function can be simplified so that it does not use a function variable, as follows:

function MySum(a,b) {Return a + b;}

Always use curly brackets around the function definition body, even if it is a single statement.

Note:

ColdFusion does not COPY any of the function arguments into the local scope of a function. However, if an unscoped variable is called, it is searched first in argument scope and then local scope.

About creating functions by using tags

You use the  cffunction  tag to define a UDF in CFML. The  cffunction  tag syntax has the following features and limitations:

  • Developers who have a background in CFML or HTML, but no scripting or programming experience are more familiar with the syntax.
  • You can include any ColdFusion tag in your function definition. Therefore, you can create a function, for example, that accesses a database.
  • You can embed CFScript code inside the function definition.
  • The  cffunction  tag provides attributes that enable you to easily limit the execution of the tag to authorized users or specify how the function can be accessed.
    The following code uses the  cffunction  tag to define the exponentiation function:
<cfargument name="exponent">
<cfreturn 2^exponent>
</cffunction>

For more information on how to use the  cffunction  tag to define a function, see Defining components and functions in CFScript.

Defining functions by using the cffunction tag

The cffunction and cfargument tags let you define functions in CFML without using CFScript. 
For information on ColdFusion components, see Building and Using ColdFusion Components. For more information on the cffunction tag, see the CFML Reference.

The cffunction tag function definition format

A cffunction tag function definition has the following format:

access="accessType" output="Boolean"]>
<cfargument name="argumentName" [Type="type" required="Boolean"
default="defaultValue">]
<!--- Function body code goes here. --->
<cfreturn expression>
</cffunction>

where brackets ([]) indicate optional arguments. You can have any number of  cfargument  tags.
The  cffunction  tag specifies the name you use when you call the function. You can optionally specify other function characteristics, as the following table describes:{{}}

Attribute

Description

name

The function name.

returnType

(Optional) The type of data that the function returns. The valid standard type names are: any, array, binary, Boolean, date, guid, numeric, query, string, struct, uuid, variableName, xml, and void. If you specify any other name, ColdFusion requires the argument to be a ColdFusion component with that name. ColdFusion throws an error if you specify this attribute and the function tries to return data with a type that ColdFusion cannot automatically convert to the one you specified. For example, if the function returns the result of a numeric calculation, a returnType attribute of string or numeric is valid, but array is not.

roles

(Optional) A comma-delimited list of security roles that can run this method. If you omit this attribute, ColdFusion does not restrict user access to the function.If you use this attribute, the function executes only if the current user is logged in using the cfloginuser tag and is a member of one or more of the roles specified in the attribute. Otherwise, ColdFusion throws an unauthorized access exception. For more information on user security, see Securing Applications.

output

(Optional) Determines how ColdFusion processes displayable output in the function body.If you do not specify this option, ColdFusion treats the body of the function as normal CFML. As a result, text and the result of any cfoutput tags in the function definition body are displayed each time the function executes.If you specify true or yes, the body of the function is processed as if it is in a cfoutput tag. ColdFusion displays variable values and expression results if you surround the variables and expressions with number signs (#).If you specify false or no., the function is processed as if it is in a cfsilent tag. The function does not display any output. The code that calls the function is responsible for displaying any function results.

Use cfargument tags for required function arguments. All cfargument tags must precede any other CFML code in a cffunction tag body. Therefore, place the cfargument tags immediately following the cffunction opening tag. The cfargument tag takes the following attributes:

Attribute

Description

name

The argument name.

type

(Optional) The data type of the argument. The type of data that is passed to the function. The valid standard type names are any, array, binary, Boolean, date, guid, numeric, query, string, struct, uuid, and variableName. If you specify any other name, ColdFusion requires the argument to be a ColdFusion component with that name. ColdFusion throws an error if you specify this attribute and the function is called with data of a type that ColdFusion cannot automatically convert to the one you specified. For example, if the argument type attribute is numeric, you cannot call the function with an array.

required

(Optional) A Boolean value that specifies whether the argument is required. If set to true and the argument is omitted from the function call, ColdFusion throws an error. The default value is false. The required attribute is not required if you specify a default attribute.Because you do not identify arguments when you call a function, all cfargument tags that specify required arguments must precede any cfargument tags that specify optional arguments in the cffunction definition.

default

(Optional) The default value for an optional argument if no argument value is passed. If you specify this attribute, ColdFusion ignores the required attribute.

Note:

The cfargument tag is not required for optional arguments. This feature is useful if a function can take an indeterminate number of arguments. If you do not use the cfargument tag for an optional argument, reference it by using its position in the Arguments scope array. For more information see Working with arguments and variables in functions.

Using a CFML tag in a user-defined function

The most important advantage of using the  cffunction  tag over defining a function in CFScript is that you can include CFML tags in the function. Thus, UDFs can encapsulate activities, such as database lookups, that require ColdFusion tags. Also, you can use the  cfoutput  tag to display output on the calling page with minimal coding.

Note:

To improve performance, avoid using the cfparam tag in ColdFusion functions. Instead, use the cfset tag.

The following example function looks up and returns an employee department ID. It takes one argument, the employee ID, and looks up the corresponding department ID in the cfdocexamples Employee table:

<cfargument name="empID" required="true" type="numeric">
<cfset var cfdocexamples="">
<cfquery dataSource="cfdocexamples" name="deptID">
SELECT Dept_ID
FROM Employee
WHERE Emp_ID = #empID#
</cfquery>
<cfreturn deptID.Dept_ID>
</cffunction>

Rules for function definitions

The following rules apply to functions that you define using CFScript or the  cffunction  tag:

  • The function name must be unique. It must be different from any existing variable, or UDF, except that you can use the ColdFusion advanced security function names.
  • You can have a user-defined function with the same name as a built-in function for a CFC but not for CFM.
  • You cannot use the following names to create user-defined functions:
    • writedump
    • writelog
    • location
    • throw
    • trace
  • The function name must not start with the letters cf in any form. (For example, CF_MyFunction, cfmyFunction , and cfxMyFunction are not valid UDF names.)
  • You cannot redefine or overload a function. If a function definition is active, ColdFusion generates an error if you define a second function with the same name.
  • You can nest function definitions; that is, you can define one function inside another function definition. See examples below.
  • The function can be recursive, that is, the function definition body can call the function.
  • The function does not have to return a value.
    You can use tags or CFScript to create a UDF. Each technique has advantages and disadvantages.

Using cfscript

<cfscript>
       function hypotenuse(a, b) {
               function square(x) { return x*x; }
               return sqr(square(a) + square(b));
            }
            
            
               result = hypotenuse(1,2);
               writeoutput(result);
           
</cfscript>

Using cffunction tag

<!---hypotenuse.cfc--->
<cfcomponent>
       <cffunction name="calchypotenuse">
             <cfargument name="a" required="true"/>
             <cfargument name="b" required="true"/>
                    <cffunction name="square">
                           <cfargument name="x" required="true"/>
                           <cfreturn x*x/>
                    </cffunction>
                    <cfreturn sqr(square(a) + square(b))/>
       </cffunction>
</cfcomponent>
<!---hypotenuse.cfm--->
<cfset myhypotenuse=new hypotenuse()>
<cfoutput>#myhypotenuse.calchypotenuse(1,2)#</cfoutput>

Immediately Invoked Function Expression (IIFE)

An Immediately Invoked Function Expression (IIFE) is a way to execute functions immediately, as soon as they are created. IIFEs do not pollute the global object, and they are a simple way to isolate variable declarations.

For more information, see the Wikipedia definition of IIFE.

  • IIFE is a self executing anonymous function block .
  • IIFEs have their own scope i.e., the variables you declare in the Function Expression will not be available outside the function.
  • Similar to other functions, IIFEs can also be named or anonymous, but even if an IIFE does have a name it is impossible to refer/invoke it.
  • Once used an IIFE can't be reused.
  • An Immediately Invoked Function Expression is a good way at protecting the scope of your function and the variables within it. 

Before proceeding to IIFE, let’s recap and see what a typical function declaration looks like.

function doSomething(){ 
   // ...do something... 
}

The other way is to create a function via a function expression.

doSomething = function(){ 
  // ...do something... 
} 

In an IIFE, a typical function declaration looks like below:

(function(){ 
    // ...do something... 
})() 

Let us deconstruct the above expression.

(function(){ 
    // ...do something... 
}) 

By wrapping the function in the parentheses, ColdFusion evaluates the expression as a function expression, not a function declaration.

Now, let’s see what the second set of parentheses is used for.

(function(){ 
    // ...do something... 
})()

The second set of parentheses immediately invokes the function. In a nutshell, in an IIFE, the expression is evaluated within the first set of parentheses and is invoked within the second set of parentheses.

Why IIFE

An Immediately Invoked Function Expression protects the scope of your function and the variables within it.

Let’s see how scope is defined in the following types of functions:

Normal function

<cfscript> 
    // function Definition 
    function addTogether() { 
        x = 20 
        y = 20 
        answer = x + y 
        writeOutput(answer) 
    } 
   // function invocation 
   addTogether() 
</cfscript>

Output

40

Closure

<cfscript> 
    // closure Definition 
    func = function () { 
        x = 20 
        y = 20 
        answer = x + y 
        writeOutput(answer) 
    } 
    // closure invocation 
    func() 
</cfscript> 

Output

40

IIFE

<cfscript> 
    (function addTogether() { 
        x = 20 
        y = 20 
        answer = x + y 
        writeOutput(answer) 
    })() 
</cfscript> 

Output

40

IIFEs have their own scope, i.e., the variables you declare in the function expression will not be available outside the function.

Like other functions, IIFEs can also be named or anonymous and can have parameters.

Once used, an IIFE can't be reused.

Examples

Closure

<cfscript> 
    // Normal function expression 
    function printOutput(){ 
        writeOutput("Hello") 
    } 
    printOutput() 
 
    //Using IIFE 
    writeoutput((function(name) { 
        return( "Hello #name#" ); 
    })("Darkness, my old friend!<br>")); 
</cfscript>

Output

Hello

Hello Darkness, my old friend!

Named closure

<cfscript> 
    // IIFE 
    (function(name) { 
        writeOutput("Hello " & "#name#") 
    })("Joker<br/>"); 
 
    // named function 
    (function printName(name) { 
        writeOutput("Hello " & "#name#") 
    })("Batman<br/>"); 
</cfscript> 

Output

Hello Joker

Hello Batman

Lambda function

<cfscript> 
    // using lambda 
    ((name)=> { 
        writeOutput("Hello " & "#name#") 
    })("Joker<br/>"); 
 
    // lambda- two parameters 
    ((fName,lName)=>{ 
        writeOutput("Hello " & fName & " " & lName) 
    })("Bruce","Wayne") 
</cfscript> 

Output

Hello Joker

Hello Batman

Statements in Lambda

<cfscript> 
    // simple statement 
    (()=>{ 
        writeOutput("Hello IIFE") 
    })() 
 
    // assignment statement 
    x=(()=>2)() 
    writeOutput("<br/>" & x) 
</cfscript>

Output

Hello IIFE

2

Operators in Lambda

<cfscript> 
    // ternary operator 
    ((a,b)=>{ 
        c = (a < b) ? a : b 
        writeOutput(c) 
    })(20,10) 
 
    // unary operator 
    unOp=(()=>13)() 
    writeOutput(unOp) 
</cfscript> 

Output

10

13

Binary operator

<cfscript> 
    // binary operator 
    // AND 
    ((a,b)=>{ 
        c=a && b 
        writeOutput("a && b is: " & c) 
    })(6,1) 
 
    // OR 
    ((a,b)=>{ 
        c=a || b 
        writeOutput("a || b is: " & c) 
    })(6,1) 
 
    // XOR 
    ((a,b)=>{ 
        c=a XOR b 
        writeOutput("a xor b is: " & c) 
    })(6,1) 
</cfscript> 

Output

a && b is: 1a || b is: 6a xor b is: NO

Assignments

<cfscript> 
    // simple assignment 
    (()=> {writeOutput("This is a simple assignment<br/>")})() 
    // multi assignment 
    d = 3 
    a=b=c=d*(() => 5)() 
    writeOutput(a) 
</cfscript> 

Output

This is a simple assignment

15

Statement and parameters

<cfscript> 
    // single param, single statement 
    writeOutput((name => "Hello, #name#")("Joker")) 
    // multiple params, single statement 
    func=(( name, lastname ) =>  "Hello, #name# #lastname#")("Tony", "Stark") 
    writeOutput(func) 
    // multiple params, multi statement 
    func1=(( name, lastname ) => { 
        return "Hello, #name# #lastname#" 
    })("Jimmy", "Page") 
    writeOutput(func1) 
</cfscript> 

Output

Hello, Joker

Hello, Tony Stark

Hello, Jimmy Page

UDF

<cfscript> 
    // As a return statement in UDF 
    function plusTwo(num) { 
        return (() => num + 2)()    
    } 
    writeOutput(plusTwo(5) & "<br>") 
 
    // As a param to built-in / UDF methods 
    myStringVar = UCase((() => " more sleep!")()) 
    writeOutput(myStringVar) 
</cfscript> 

Output

7

MORE SLEEP!

If-else

<cfscript> 
    // if-else statement 
    if((function () {return "orange"})() == "banana"){ 
        writeOutput("Fruit is orange!" & "<br/>") 
    } 
    else{ 
        writeOutput("Fruit is something else") 
    } 
</cfscript>

Output

Fruit is something else

Recursive IIFE

<cfscript> 
    // recursive IIFE 
    writeoutput(((param) => param + 15)((() => 13)())) 
</cfscript>

Output

28

For loop

<cfscript> 
    // for loop 
    for (i=1;i<=(()=>5)();i++){ 
        writeOutput(i & ". " & "Hello World" & "<br/>") 
    } 
</cfscript>

Output

1. Hello World

2. Hello World

3. Hello World

4. Hello World

5. Hello World

Implicit initialization

<cfscript> 
    // Array implicit initialization 
    arr = [ 
            (()=> 1)(),  
            (()=> 2)(),  
            (()=> 3)() 
    ] 
    writeDump(arr) 
 
    // Struct impicit initialization 
    str={ 
        "a":(()=>1)(), 
        "b":(()=>2)(), 
        "c":(()=>3)() 
    } 
    writeDump(str) 
</cfscript> 

Output

IIFE

Get help faster and easier

New user?