Migrating From CFML
A quick guide on key differences and issues when migrating from CFML
Please note that our CFML Compatibility is still in progress. Please keep this page bookmarked as we progress to our stable release.
BoxLang is a new language with a dual parser to support the CFML ecosystem. It also has a compatibility module (bx-compat
) that will allow the BoxLang runtime to behave like an Adobe or Lucee Server. We also recommend you read the Quick Syntax Style Guide to give you an understanding of all the new features of BoxLang.
You can install the compatibility module using box install bx-compat
or if you have a server.json
you can add the following:
Even if you forget the server, when you start it up, it’ll get the compatibility module automatically.
File Types
BoxLang can parse and run all of the traditional CFML file types
.cfc
- Components.cfs
- Scripts.cfm
- Templates
Components are Classes
CFML Components (CFCs) are called classes in BoxLang, like any other language. You can also use the class
declaration for them. You can continue to write components if you like, but if you use our .bx
extensions, they are now classes.
Tags are Components
Since BoxLang is not a tag-based language but a dynamic language offering a templating language. There are no concepts of tags but of BoxLang components that can be accessed via our templating language or script. In CFML the templating language uses a <cf
prefix, in BoxLang we use a <bx:
prefix.
Default assignment scope
In CFML, the default assignment scope is always variables
, but in BL it can differ based on the context. For Functions, it will be local
. The BoxLang runtime will toggle this behavior based on the type of the compiled source code. So for .cfm
or .cfc
source files, the default assignment scope in functions will remain variables
but for code compiled from .bx
, .bxs
or .bxm
files, the default assignment scope in functions will be local
.
CastAs operator
BoxLang has a new castAs
binary operator that you can use instead of the javaCast()
bif.
No transpilation changes are needed since this is a BL-only feature.
Multiple catch types
BoxLang supports
No transpilation changes are needed since this is a BL-only feature.
Annotations
BoxLang will allow for proper annotations before UDF declarations, properties, and classes. The annotation's value can be a string, struct literal, or array literal. You can also use multi-spaced or indentation.
No transpilation changes are needed since this is a BL-only feature.
Documentation Comments (Javadoc style)
BL will support documentation comments like CF, but will NOT allow them to actually influence the function’s behavior. When transpiling CFML to BL, any annotations set in a doc comment modifying the function or any arguments need to be moved to proper annotations in BL.
So the CFML
would turn into this BoxLang
Function output defaults to false
The output
of functions will be false in BL. The BoxLang runtime will toggle this behavior based on the type of the compiled source code. So for .cfm
or .cfc
source files, default value of the output
annotation on classes and functions will remain true
but for code compiled from .bx
, .bxs
or .bxm
files, the default value of the output
annotation on classes and functions will be false
.
Note, if your Application.cfc
and onRequestStart()
method do not specify
you will get a blank page with no output!
Import keyword
CFML has the import tag, but there doesn’t seem to be any special script version of it, ours looks like this:
Import Aliases
You can also import classes from any resolver and attach an alias to remove any ambiguity.
Object Resolvers
Any import
or new
can be prefixed with an object resolvers prefix. A resolver adheres to our resolver interface to provide access into any type of object or filesystem. By default we ship with two resolvers:
java
: Java classesbx
: BoxLang classes
This allows you to import or easily create classes from any source.
This will allow us to modularly provide object resolvers for any type of integrations. You will also be able to use the resolvers for extends
and implements
Auto-casting argument and return value types
In CF an argument or return value of Numeric will allow a String through untouched so long as that string can be cast to a number. In BoxLang, we are actively casting the value to a “real” number. In theory, this is seamless, but could affect if you are checking the underlying Java type or passing to a Java method. There is no transpilation that can undo this, unless we add some setting or runtime configuration to disable the “feature”.
GetCurrentTemplatePath() and relative includes
Both Adobe and Lucee do not agree with each other and are inconsistent even within themselves regarding
The return value of the
getCurrentTemplatePath()
BIFThe lookup of relative templates being included
The lookup of relative CFC paths for object instantiation
Here is some documentation on their differences:
Given a method that's originally part of a CFC
getCurrentTemplatePath() returns the original CFC (Adobe and Lucee agree here)
new RelativeCFC()
find CFCs in the same folder as the original CFC (Adobe and Lucee agree here)include "relativePath.cfm";
find CFCs in the same folder as the original CFC (Adobe and Lucee agree here)
Given a UDF defined in a file in a different directory that's injected into another CFC
getCurrentTemplatePath()
returns the original birthplace of the UDF source in Lucee
returns the new CFC the UDF was injected into in Adobe
Relative CFC path resolution
finds the CFC relative to the original birthplace of the UDF source in Lucee
finds the CFC relative to the NEW CFC's path in Adobe
Relative cfinclude path resolution
finds the CFC relative to the original birthplace of the UDF source in Lucee
finds the CFC relative to the original birthplace of the UDF source in Adobe
Given a UDF defined in a file in a different directory that's passed into a UDF in another CFC for invocation
getCurrentTemplatePath()
returns the new CFC the UDF was injected into in Lucee
returns the new CFC the UDF was injected into in Adobe
Relative CFC path resolution
finds the CFC relative to the original birthplace of the UDF source in Lucee
finds the CFC relative to the NEW CFC's path in Adobe
Relative cfinclude path resolution
finds the CFC relative to the original birthplace of the UDF source in Lucee
finds the CFC relative to the original birthplace of the UDF source in Adobe
In BoxLang, this is being simplified and made consistent across the board. In ALL cases the “current template path” and relative lookup directory will tie to the original source path on disk of the file that contains the currently executing code. So, whether it’s an include, a UDF, an injected UDF from another location, or a closure defined elsewhere - whatever original source file for the code in question is what determines the “current template path” and relative lookups.
BIF Renaming
Some bifs have been renamed in BoxLang.
CFML | BoxLang |
---|---|
serializeJSON | jsonSerialize |
deserializeJSON | jsonDeserialize |
chr | char |
asc | ascii |
getComponentMetadata | getClassMetadata |
CreateObject Types
The component
type for create object becomes class
in BoxLang
JDBC Queries
Parameter SQL Types
Both Adobe ColdFusion and Lucee Server utilize a cfsqltype
key on query parameters to denote the type of the value being used in a prepared statement or query:
In BoxLang, you'll need to replace cfsqltype
with just sqltype
. In addition, we'd prefer to see all usage of the cf_sql_
/CF_SQL
prefixes stripped:
Here's a full breakdown of the various syntaxes:
sqltype:"numeric"
- The preferred syntax.cfsqltype:"cf_sql_numeric"
- will throw an error in BoxLang core. In CFML syntax files, is transpiled tosqltype:"cf_sql_numeric"
.sqltype:"cf_sql_numeric"
- is silently treated assqltype:"numeric"
.
BlockFactor Query Option
The blockfactor
query option in Adobe CF and Lucee Server is used to set a custom batch size when selecting large numbers of rows:
In BoxLang, this is renamed to fetchSize
:
You can use the blockfactor
nomenclature by installing the bx-compat
module.
Last updated