This Blog contains details about the Language Enhancements done in ColdFusion 2025 release.
This blog covers the language enhancements in ColdFusion 2025.
This blog post is the second in the series detailing the enhancements made to ColdFusion Markup Language for the ColdFusion 2025 release. To explore other enhancements, please refer to this blog post.
Operators : Elvis and Null Coalescing
The ColdFusion 2025 release introduces the Null Coalescing Operator (??) and an enhanced Elvis Operator (?:). Previously, there were requests to distinguish between Elvis and Null Coalescing Operators. To ensure backward compatibility, we have now added the Null Coalescing Operator (??).
- Elvis and Ternary Operators are now failsafe.
- CFML Elvis Operator uses Truthy Values.
- Null Coalescing Operator (??) handles null values by returning the RHS expression.
- Byte Code generation is optimized, reducing classes per Elvis Operator.
To demonstrate the Elvis FailSafe Operator with an example: previously, the Elvis Operator would throw an exception if a developer tried to access an undefined value. Currently, it assigns the right-hand side expression to the value. The code snippet below illustrates this:
<cfscript>
company = [
/* {
employees: [
{
Name: "John",
Department: "Payroll"
}
]
} */
];
writeOutput("Employee Department:");
department = company[1].employees[1].Department ?: "No Information";
writeOutput(department);
</cfscript>
You may uncomment the code provided above to observe the outcome.
Here’s an example showing the number of classes generated by the code snippet before and with ColdFusion 2025.
<cfscript>
function getfoo() {
writeoutput("inside foo : "); return "foo";
}
function getbar() {
writeoutput("inside bar :");
return "bar";
}
elvis = getbar() ?: "hello";
writeOutput(elvis);
writeOutput("<br>");
ternary = getbar() ? getfoo(): "hello";
writeOutput(ternary);
</cfscript>
We will observe that one fewer class per Elvis/Ternary operator is generated, resulting in a reduction of bytecode and thereby optimizing the Byte Code Generation process.
For the Null Coalescing Operator, please consider the following code snippet:
<cfscript>
local.vals = [0, false, "no", javacast("null","")];
writeDump(local.vals.map(
function(val){
return arguments.val ?? "true";
}));
</cfscript>
New Constructs : Trailing Commas and Multi Exceptions in Catch Clause
ColdFusion 2025 introduced new features like trailing commas and handling multiple exceptions in a single catch clause.
Previously, we made semicolons optional in ColdFusion. Now, we have also added support for trailing commas. Some aspects of trailing commas are:
- Easier code modifications with minimal syntax errors.
- Cleaner diffs in version control systems.
- Allowed trailing commas in array/struct literals, parameter definitions, function calls, and array/object destructuring.
- No trailing commas after Rest parameters.
Trailing commas can be used like this:
<cfscript>
arr = [1,2,];
writeDump(arr);
</cfscript>
<cfscript>
structVar = [ {name: "Hank"},{name: "Dale"},];
writedump(structVar);
</cfscript>
<cfscript>
structObj = {foo: 42, bar: true,};
({ bar, foo, } = structObj);
writedump(bar)
</cfscript>
The ColdFusion 2025 release has improved the CFML Language by adding support for handling multiple exceptions in a single catch clause. This enhancement reduces duplicate code and improves readability. Additionally, it generates less bytecode due to the absence of redundant code. Both script and tag-based formats are supported, using the | sign as the delimiter.
The code for this is provided below:
<cfscript>
try {
// emp = CreateObject("Java", "Employees");
val = 5/0;
} catch( DivideByZero| Expression ex) {
writeOutput("The application was unable to perform a required operation.<br>
Please try again later.<br> #ex.Message#<br>");
} catch(any anyex) {
writeOutput(anyex.Message);
writeOutput("Any Exception");
} finally {
writeoutput("<br>Thank you for visiting our web site.<br>come back soon!");
}
</cfscript>
Built In Functions ( BIFs ):
The ColdFusion 2025 release has introduced and improved several built-in functions.
-
- StructValueArray( myStruct )
- listgetduplicates( list, delimiter, ignorecase )
- getPropertyFile( path )
- getPropertyString( path, key )
- setPropertyString( path, struct )
- interruptThread( threadname)
- isThreadInterrupted( threadname )
The following BIFs have been enhanced:
-
- directoryList( fileAttributesStruct )
-
Attributes: [path, type, extension, attributes, lastmodifieddate, parent, link, name, size]
-
-
Javacast(“type[][] “,input2DArray)
-
hash(string=’foo’, outputEncoding=”hex”)
-
Duplicate(object, deepCopy)
-
createObject(type, class, path)
-
DeserializeJson(json, strictMapping, useCustomSerializer, preserveCaseForStructKey)
- directoryList( fileAttributesStruct )
The parameters that are highlighted in green are the ones those were newly added.
Let’s explore some of the BIFs with the corresponding code-snippet on how it can be used by the developers.
<cfscript>
boolean function filterBySize (fileObj) {
var sizeLimit = 1024; //more than 10 KB
var extensionList = "cfm";
if( fileObj.type is "dir" ) return false;
if( DateDiff("m", fileObj.lastmodifieddate, now() ) < 10 )
{
var fileInfo = getFileInfo(fileObj.path);
if( fileObj.size <= sizeLimit )
return true;
}
return false;
}
filteredResults = directorylist( expandPath("./../.."), true, "path", filterBySize );
writeOutput("Listing Files with filtering on Size, Type and Modified Date");
writeDump(filteredResults);
</cfscript>
<cfscript>
personObj = new Person(firstName = 'Matt', lastName = 'Gifford',
address = {"street" : 20,"village": "vikarabad"}
);
changeAddress = (address) => {
address["street"] = 22;
return address;
}
personObjDeepCopy = duplicate(personObj);
personObjShallowCopy = duplicate(personObj, false);
personObj.setAddress(changeAddress(personObj.getAddress()));
personObj.setFirstName("Brad"); //primitive Type, hence copied.
writeDump(var=personObj, label="Person");
writeOutput("<br>");
writeDump(var = personObjDeepCopy, label="Deep");
writeOutput("<br>");
writeDump(var = personObjShallowCopy, label="Shallow");
</cfscript>
<cfscript>
list = "one,one,ONE,two,three,,four,THREE,FOUR,FIVE,";
newList = listgetduplicates(list=list,delimiter=",",ignorecase=true);
writeOutput(newlist)
</cfscript>
<cfscript>
myFile=GetDirectoryFromPath(GetCurrentTemplatePath()) & "fileout.properties"
setPropertyString(myFile, "KEY11", "value11", "UTF-8");
someStruct=StructNew();
someStruct.google = "search";
someStruct.microsoft= "windows";
someStruct.apple = "mac m1";
someStruct.amazon = "shopping";
setPropertyString(myFile, someStruct, "UTF-8");
writeDump(myFile)
</cfscript>
<cfscript>
path =GetDirectoryFromPath(GetCurrentTemplatePath()) & "fileout.properties"
writeDump("Path: " & path);
writeDump(getPropertyFile(path));
writeDump("getPropertyString name : " & getPropertyString(path,"apple"));
</cfscript>
<cfscript>
testThreadName = "thread-interrupt-action"
thread action="run" name="#testThreadName#" {
while(!isThreadInterrupted(testThreadName)){
variables.message = "thread #testThreadName# running...";
}
variables.message &= "Thread interrupted. exiting.<br>";
}
sleep(100) //allow the thread to start
writeOutput("Before interrupt, isInterrupted:" & isThreadInterrupted(testThreadName) & "<br>")
thread action="interrupt" name=testThreadName {}
thread action="join" name=testThreadName {}
writeOutput("After interrupt, isInterrupted:" & isThreadInterrupted(testThreadName) & "<br>")
writeOutput(variables.message)
</cfscript>
Additionally, I would like to emphasize an enhancement related to the `createObject` function. There is a specific use case where a developer might need to dynamically load a class without starting the server. In such scenarios, the class or jar file can be placed at a designated location and subsequently added as a parameter to the `createObject` function as follows:createObject(type, class, path)
A jar can be created with this class and placed dynamically at a specified location without starting the server.
public class CFDevelopers {
public CFDevelopers() {
}
public String print() {
return "Hello ColdFusion Developers.";
}
}
<cfscript>
sampleObject = createObject( "java", "Sample").init();
writeOutput(sampleObject.print());
writeOutput("<br><p><b>Invoking CFDevelopers Class</b><p><br>");
CFDevelopersObject = createObject(
"java", "CFDevelopers",
["#ExpandPath(".")#"]
).init();
writeOutput(CFDevelopersObject.print());
</cfscript>
In addition to the major features introduced in the ColdFusion 2025 release, several other enhancements and significant bug fixes have been implemented. Further details can be found here.
You must be logged in to post a comment.