Quick Syntax Guide
Quickly learn what the BoxLang language offers.
This guide provides a quick overview of BoxLang syntax styles, intricacies, operators, and features. It aims to assist developers from other languages in their BoxLang development journey. BoxLang has been heavily inspired by many different languages, including Java, CFML, Groovy, Kotlin, Ruby, PHP, and more.
If you are a CFML developer, check out also our CFML Guide.
Dynamic & Loose Typing
BoxLang variables are dynamic and type-inferred. We try our best to infer which type you are trying to set for variables at compile-time, but they can completely change at runtime. You use the var
keyword to specify a variable within functions or declare them inline if you are in a bxs
or bxm
script file.
File Types:
bx
- A BoxLang classbxs
- A BoxLang scripting filebxm
- A BoxLang templating markup file
You can also add types to arguments within functions or omit them, and it will default to any,
which means, well, anything:
As you can see, not only can we make arguments required or not, but we can also add default values to arguments. BoxLang does not allow method overrides since basically, every method can take an infinite number of arguments, defined or even NOT defined.
We can also do type promotions and auto-casting from types that can be castable to other types. So, if we call our function like this:
This is handy as we really really try to match your incoming data to functional arguments.
Any
by default
Any
by defaultIf they are not specifically typed, all arguments and variable declarations are of any
type. This means they will be inferred at runtime and can change from one type to another.
High Precision Mathematics
By default, BoxLang will use high-precision mathematics by evaluating your numbers and determining the right type for them. If the numbers are whole and short enough, they will be stored in an Integer
or Long
. If they contain decimals, they will be a BigDecimal
and if you do math on them, the result will be the most precise of the two inputs. You don't have to be knowing or addressing the numerical types, we will do that for you.
You can change this setting in the configuration to false and it will use basic Double mathematics and it will be up to you when to use high precision evaluations.
You can store a larger number like:
in a Double
, but behind the scenes, not all of that is stored. All Java tracks is
which means some digits of the original number are gone. So, if you run the math equation
you get:
Windows calculator:
33333333333333333333
BoxLang:
33333333333333333333
You may not be too worried about the use case of very large numbers, but the floating point math has bitten every single developer who’s been around long enough and can wreak havoc on the simplest of math calculations.
Level of Precision
Furthermore, Java’s BigDecimal class allows you to choose the level of precision you want to use. Java 21 defaults to “unlimited” precision, but we’ve dialed that back to the IEEE 754-2019 decimal128 format, which has 34 digits of precision and uses a rounding mode of HALF_EVEN. You can change the amount of precision BoxLang uses for BigDecimal operations at any time like so:
Only When Needed
BoxLang has a smart parser that will always store a number in the smallest package possible, opting to promote the type only when necessary.
The “bigger” types are contagious. So if you add together an Integer
and a Long
, we store the result in a Long
. If you add a Long
and a BigDecimal
together, we store the result in a BigDecimal
. The idea is always to keep things small and fast until we can’t any longer.
Numeric Literal Separators
Numeric placeholders allow you to place underscore characters (_
) inside of a numeric literal for readability. Take a number like this
That’s 1 billion. Or was it 1 million? Or maybe it was 100 million… pauses to re-count. With numeric placeholders, your code can look like this:
Ahh, so it was 1 billion! There are no rules on where you can place the underscores, so long as they are INSIDE the number and not leading or trailing. You can also place numeric separators in decimals:
and in the exponent of scientific notation
These underscores are thrown away at compile time. They are not represented in the bytecode and will not appear anywhere in your running app. They are purely for readability in your source code.
Case Insensitive Functionality
Most things in BoxLang can be done with no case sensitivity by default. You can enable case sensitivity in many functions and components, but we try to be insensitive as much as possible :). Here are a few observations where access is case-insensitive by nature:
variable access in any scope
function calls, even to Java classes
function arguments, even on Java classes
class creation, even on Java classes
Internally we leverage a Key
class that provides us with case insensitivity. Each map has a Key
as the, well, key.
BIFs = Built-In Functions
BoxLang is inspired by many languages and offers built-in functions you can call from anywhere in your code. BoxLang ships with a plethora of functions that can be used headlessly or as member functions on different data types. Modules can also collaborate functions globally. There is no need to import them, they are automatically imported.
Please check out the reference section for all the contributed core BIFs.
To get a sense of all the BIFs registered in your runtime, do a
writedump( getFunctionList() ) or println( getFunctionList() )
Member Functions
Member functions are special functions attached to all data types in BoxLang, whether they are structs, arrays, strings, numbers, dates, Java objects, classes, etc. We provide tons of member functions, but developers can also contribute their own via BoxLang modules. All member functions map back to built-in functions (BIFs).
You can find all the collection of member functions in our types section.
BoxLang Components
Components are a special construct in BoxLang that allows the core and modules to contribute functionality that cannot be expressed in a simple BIF. This is for more complex contributions to the language like HTTP frameworks, FTP, Email, PDF tooling, Image tooling, etc. A simple BIF would not cut it. These components can be called from anywhere in your source code, either in the script or in the templating language. Components usually are statements and not expressions. They also allow you to have bodies that can produce output if needed.
As you can see, they all start with the prefix of bx:
and the name of the registered component. Each component can have attributes and nested components as well. The cool thing about components, is that they translate incredibly well for templating so that you can create rich templating tags as well.
We ship several components as core:
Abort
- Abort the requestApplication
- Update/Configure the running virtual applicationAssociate
- Associate variable data with a child or parent componentCache
- Caches contentDirectory
- Directory-based callsDBInfo
- Get database metadata and informationDump
- A cool UI/console dumper of data, simple or complexExecute
- Execute OS binariesExit
- Exit from nested executions of componentsFile
- File-based callsFlush
- Force flush the output buffer in BoxLang either to Web or Console or whatever runtime you are on.HTTP
- HTTP CallsInclude
- Include another template file into another template. Inception.Invoke
- Invoke dynamic methods on dynamic objects with dynamic argumentsLock
- Easy code locking and segmentationLog
- Write to our log filesLoop
- Looping constructs for native or Java typesModule
- Call custom templates in an isolated fashionObject
- Create BoxLang, Java, Custom objectsOutput
- Wrap code/HTML to produce output to the buffersParam
- Parameterize variables with default values if not definedQuery
- Execute quick queriesSaveContent
- Execute content and save it's output into a variable using template stylingsSetting
- Set global BoxLang setting directivesSilent
- Wrap code so it doesn't produce any output or whitespaceSleep
- Sleeps the thread for the requested amount of timeStoredProc
- Execute stored proceduresTransaction
- Start JDBC Transaction demarcationsTimer
- Time code between itThread
- Create threaded codeThrow
- Throw an exceptionTrace
- Trace debugging messages to the console or debugging facilitiesXML
- Build or work with XML contentZip
- Allows you to compress/uncompress and manipulate zip/gzip files
However, check out our modules section for more components, and you can also build your own.
Expression Interpolation
BoxLang can interpret ANYTHING within #
as an expression. This can be used for output, assignments, and much more.
Multi-Line Strings
In Java, you can declare a multi-line string easily (JKD15+) by using the triple ("""
) quote marks.
It is by far the most convenient way to declare a multiline string as you dont have to deal with line separators or indentation spaces. In BoxLang, you only need 1 quote ("
), we will take care of the rest!
Multi-Variable Assignments
BoxLang supports the concept of multi-variable declaration and assignments by just cascading variables using the =
operator.
This will create the 3 variables in the variables
scope with the value "I am Spartacus!"
Switch Statements
The BoxLang switch statements can work on any literal but also on any expression
Catch `any` exception
BoxLang allows you to catch any
exception using our any
operator
Multi-Catch Exceptions
In BoxLang you can catch multiple exceptions by using the pipe | operator. They can be both BoxLang exceptions or Java exception types:
No Semicolons, almost
Semicolons are almost always optional except in some situations:
property
definitions in classesComponent calls with no body
Component child calls
Components in BoxLang have contributed functionality that is not core language and can be used in a statement syntax. Examples are mail, http, ftp, etc.
Scopes
BoxLang offers many different persistence and variable scopes depending on where and what you are. All scopes in BoxLang are backed by the Map interface, which in BoxLang land are called Structures. They are case-insensitive by default; you can pass them around as much as you like.
Scripts (bxm, bxs
)
bxm, bxs
)Scripts can be written in full script (bxs
) or using our templating language (bxm
).
variables
- Where all variables are storedUnscoped variables go to the
variables
scope in a script
Classes
BoxLang supports all Object-oriented constructs know in several languages. We expand on the areas of metaprogramming and dynamic typing.
variables
- The private scope of the classthis
- The public scope of the class and also represents the instancestatic
- The same as Java, a static scope bound to the blueprint of the classUnscoped variables go to the
variables
scope in a class
Functions/Lambdas/Closures
BoxLang supports 3 types of Functions.
local
- A local scope available only to the functionarguments
- The incoming argumentsvariables
- Access to the script or class private scopethis
- Access to the class public scopeUnscoped variables go to the
local
scope in a function by default
Persistence Scopes
BoxLang and some of it's runtimes also offer out of the box scopes for persistence.
session
- stored in server RAM or external storage tracked by a unique visitorclient
- stored in cookies, databases, or external storages (simple values only)application
- stored in server RAM or external storage tracked by the running BoxLang applicationcookie
- stored in a visitor's browser (Web Only)server
- stored in server RAM for ANY application for that BoxLang instancerequest
- stored in RAM for a specific request ONLYcgi
- read-only scope provided by the servlet container and BoxLang (Web Only)form
- Variables submitted via HTTP posts (Web Only)URL
- Variables incoming via HTTP GET operations or the incoming URL (Web Only)
Please visit our scopes section to find out much more about scopes in BoxLang.
Scope Hunting
When you access a variable without specific scope access, BoxLang will try to find the variable for you in its nearest scope. This is done internally via a context object, which can be decorated at runtime depending on WHERE the code is being executed (CLI, web, lambda, android, etc) Example:
Check out our Scopes section to learn more about scope hunting.
Full Null Support
null
is a real thing! It's nothing but real! We support the null
keyword, assignments, and usage just like Java. It follows the same rules.
CastAs Operator
BoxLang has a natural casting operator that is fluent and readable: castAs {expression}.
It can be an expression since the right-hand side can be dynamic. Unquoted identifers will be considered a string literal. Any other expression will be evaluated at runtime.
You can also use our handy javaCast
()
BIF if you need to, but this is integrated into the language.
Human Operators
You can see all the supported operators on our operator's page. We have several fluent operators using English instead of symbols, and some that are only English-based. You can see all the supported operators on our operator's page.
==
eq
!=, <>
neq
>
gt
>=
gte
<
lt
<=
lte
contains, ct
Returns true if the left operand contains the right one.
'hello' contains 'lo'
does not contain, nct
Negated Contains
!
not
&&
and
||
or
XOR
Exclusive OR
EQV
Equivalence
IMP
Implication
%
mod
Modulus
InstanceOf Operator
Like other languages, we also offer an instanceOf
operator alongside a nice BIF: isInstanceOf()
. You can also use negation using our lovely not
operator.
Data Types
All Java types can be used alongside the core BoxLang types:
any
array
UnmodifiableArray
binary
boolean
class
closure
date
double
guid
function
float
integer
lambda
numeric
number
query
UnmodifiableQuery
string
struct
UnmodifiableStruct
uuid
Arrays are Human
Arrays in BoxLang start at 1, not 0. End of story!
Array/Struct Initializers
Arrays and Structs in BoxLang can be created using literal constructs. Please note that values within the literal declarations can also be expressions.
Truthy/Falsey
BoxLang Truthy and Falsey are concepts used in programming to determine the "truth" of a value in a Boolean context. In many programming languages, values other than true and false can be evaluated for their truthiness. Understanding truthy and falsey values is crucial for writing effective and accurate code when evaluating conditions or performing logical operations.
Truthy values
positive numbers (or strings which can be parsed as numbers)
boolean true
string “true”
string “yes”
array with at least one item
query with at least one row
struct with at least one key
Falsey values:
A
null
valueThe number 0 or string “0”
boolean false
string “false”
string “no”
empty arrays
empty queries
empty structs
Imports & Class Locators
BoxLang offers the ability to import both BoxLang and Java classes natively into scripts or classes.
Works just like Java. However, you will notice a nice java:
prefix. This is called an class locator prefix. BoxLang supports these out of the box:
java:
- Java classes to import or instantiatebx:
- BoxLang classes to import or instantiate (Default, not required)
You can also remove the java:
prefix and BoxLang will try to locate the class for you. Careful, as it will scan all locations.
Import Aliases
You can also alias imports to provide less ambiguity when dealing with classes with the same name:
All the object resolvers prefixes can be used anywhere a class or path is expected:
Creating classes and instances:
createObject(), new
Using
imports
Extending classes
Implementing interfaces
Null Coalescing aka Elvis Operator
BoxLang supports the null coalescing operator ?:
to allow you to evaluate if values are empty or null. This is not a shortened ternary as other languages.
This tests the left-hand side of the ?:
and if its null
then it will evaluate the rigth expression or value. This can be used on if statements, assignments, loops, etc.
Safe Navigation Operator
BoxLang supports safety navigation on ANY object that can be dereferenced: structs, maps, classes, etc. This basically allows you to test if the value exists or not and continue dereferencing or return null
Imagine how tedious this code is
Now let's transform this code:
Assert
BoxLang offers an assert
operators that will evaluate an expression and if the expression is falsey it will throw an assert exceptions.
Functional
BoxLang functions are first-class citizens. That means you can pass them around, execute them, dynamically define them, inject them, remove them, and so much more.
It has three major functional types:
UDF—User-Defined Function—Can be created on any scripting template or within Classes. They carry no context with them except where they exist.
Closures are named or anonymous functions that carry their surrounding scope and context with them. It uses the fat arrow
=>
syntax.Lambdas are pure functions that can be named or anonymous and carry NO enclosing scope. They are meant to be pure functions and produce no side effects. Data in, Data out. It uses the skinny arrow
->
Syntax.
Let's write up another script that leverages closures and lambdas.
Public
by default
Public
by defaultAll functions and classes are public
by default, so there is no need to add the public
identifier if you don't want to. This creates a very nice and low-verbosity approach to function declaration:
Non-required arguments by default
All arguments are NOT required by default and will be defaulted to null
if not passed. You can use the required
identifier to mark them as required.
Default Arguments
You can create defaults for arguments, which can be literal or actual expressions:
Argument Collections
Similar to var arguments in Java, BoxLang allows the arguments
scope to be completely be variable. meaning you can declare the arguments, but you can pass as many as you like and they will all be added into the arguments
scope.
Another feature is that you can bind and apply these arguments at function execution time from any map or structure via the argumentCollection
special argument. This allows you to collect arguments and dispatch the function call, and BoxLang will match the argument names for you. This can be great for dynamic argument collection, form collection, JSON packets, etc.
This is a great time saver.
Auto-casting Arguments & Return Values
In BoxLang, we actively cast the incoming argument value to the specified declared argument.
BoxLang will try to auto cast the incoming argument to the numeric
type in this instance.
It will also auto cast the outgoing return value for you. So if your function specifies that the return value is a boolean, but you return a string, it will auto cast it to boolean for you.
BoxLang Classes
BoxLang classes are enhanced in many capabilities compared to Java, but they are similar to Groovy and CFML.
Automatic
package
definitionAutomatic Hash Code and Equals methods
Automatic constructor created for you based on the defined
properties
No need to add a name to the
class
definition, we use the filenameImplements by default
IClassRunnable, IReferenceable, IType, Serializable
Automatic getters and setters for any
property
definitionAutomatic implicit property accessors and mutators
Allows for pseudo constructor blocks for initializations and more (Space between last property and first function)
Output is false by default for pseudo-constructors and functions
Automatic metadata registration into the
$bx
BoxMeta programming objectAllows for single inheritance
Allows for interfaces
Allows for
static
blocks, functions, and propertiesAllows for
final
properties (coming soon)Allows for
lazy
properties (coming soon)Allows for property observers (coming soon)
Allows for scope observers (coming soon)
Functions in a class can have different visibilities:
private, public, protected, remote
Check out our Classes section for further information
Properties, not Fields
BoxLang classes can define properties as data members; they are not called fields and are always private
meaning they will be stored in the variables
scope. You can define them in short or long format. Please note that properties do require a semi-colon, as they can be very ambiguous.
All properties are stored in the variables
scope.
Short Form
The short form allows for property [type=any] name [default=expression];
Long Form
The long form allows for name-value pairs. We distinguish some value pairs from those we don't, and those we don't will be added as metadata to the property.
Check out our properties section for all valid attributes. Here are a few common ones
default
- The property's default valuename
- The property's namegetter
- Boolean indicator to generate or not the getter for the property. Default is truerequired
- If the property requires a value or not.setter
- Boolean indicator to generate or not the setter for the property. Default is truetype
- The default type of the property defaults toany
BoxLang also advertises Class creations, so modules can collaborate with extra metadata and properties or inspect the properties and act on them.
Our dependency injection framework does this.
Automatic Constructor
Constructors in classes for BoxLang are not overloads but a single init()
method. However, by default we create one for you. It can also take in named parameters or an argumentCollection
to initialize all properties.
If you create your own init()
then it's your job to initialize your class :)
Annotations
BoxLang annotations can be added to properties
, functions
, and classes
. Using the following pattern:
The value
is a literal expression (string, boolean null, number, array, or struct) or an identifer. Since runtime variables aren't allowed here, identifiers will be treated as quoted strings. If no value is supplied, then omit the parentheses.
Tip: Remember that string literals you can use quotes, single quotes or none.
You can add as many as you like to the target locations without creating annotation classes or boilerplate.
Metadata: $bx
All of these annotations and metadata can be retrieved at runtime by using the getMetadata()
or getClassMetadata()
bifs. You can also look at the .$bx
property in every boxlang object. Which contains not only the metadata about each object, but ways to do meta-programming with it. Like adding/modifying/removing properties/functions/annotations.
Extra metadata can be added to functions, properties, classes, or annotations.
The $bx
object is the BoxLang meta-object. It contains all the necessary metadata information about an object, it's Java class representations and useful methods for meta-programming. From it's Java Class, to functions, properties, data, etc. It can be used on ANY BoxLang Type. Here are the properties in the $bx
object available to you. It also contains many methods that exist in the BoxMeta
object.
meta
- A struct of metadata about the class$class
- The JavaClass
that represents your class
Getter and Setters
By default, automatic getters and setters for properties are enabled. You can disable them all for the class or one by one. All the setters return an instance of this
. You can also override them as you see fit.
Implicit Accessors
Implicit accessor/mutator invocations are on by default in BoxLang. You can disable them by adding the invokeImplicitAccessor
annotation to false. Implicit accessors allows you to invoke getters and mutators as if you are working properties on a class. It's just syntactical sugar to make your code look a lot less verbose when calling getters and setters.
Last updated
Was this helpful?