Comment on page

# Operators

Operate all things++--==!^%/\
Operators are the foundation of any programming language. Operators are symbols that help a programmer to perform specific mathematical, structuring, destructuring, and logical computations on operands (variables or expressions). We can categorize the CFML operators into the following categories:
1. 1.
Arithmetic/Mathematical
2. 2.
Assignment
3. 3.
Logical
4. 4.
Comparison
5. 5.
Ternary
6. 6.
Elvis (Null Coalescing)
7. 7.
Function
8. 8.
Collections
You will see that CFML does not have native bitwise operators, but it does implement bitwise operations via functions since functions can also be operators in CFML: `bitAnd, bitMaskClear, bitMaskRead, bitMaskSet, bitNot, bitOr, bitSHLN, bitSHRN, bitXOR` . You can find much more information here: https://cfdocs.org/math%2Dfunctions
CFML does not offer the capability to overload operators like other languages.

## Operator Precedence

The order of precedence exists in CFML, just like in mathematics. You can also control the order of precedence by using the grouping operator `()` like in mathematics, the magical ordering parenthesis.
1
^
2
*, /
3
\
4
MOD
5
+, -
6
&
7
EQ, NEQ, LT, LTE, GT, GTE, CONTAINS, DOES NOT CONTAIN, ==, !=, >, >=, <, <=
8
NOT, !
9
AND, &&
10
OR, ||
11
XOR
12
EQV
13
IMP
Remember that using parenthesis `(Grouping Operator)` is very important to denote precedence.

## Arithmetic Operators

These operators are used to perform arithmetic/mathematical operations on operands.
Operator
Name
Description
`+`
`a = 1 + 4`
`-`
Subtract
`a = 4 - 2`
`*`
Multiply
`a = 4 * b`
`/`
Divide
`a = 4 / myVariable`
`^`
Exponentiate
`a = 2^2 // 4`
`%, MOD`
Modulus / Remainder
`5 % 2 = 1` or `5 mod 2`
`\`
Integer Divide
`a = 7 \ 3` is 2. Please note it does not round off the integer.
`++`
Increment
`a = b++` assign b to a and THEN increment b `a = ++b` increment b and THEN assign to a
`--`
Decrement
`a = b--` assign b to a and THEN decrement b `a = --b` decrement b and THEN assign to a
`-`
Negate
`a = -b` Negate the value of b
`+`
Positive
`a = +b` Make the value of b a positive number
`()`
Grouping
The grouping operator is used just like in mathematics, to give precedence to operations. `result = 3 * (2+3)` which is not the same as `result = 3 * 2 + 3`

## Assignment Operators

These operators are usually used for compound evaluations and assignments.
Operator
Name
Description
`=`
Assignment
`a = 5` The way to assign a value to a variable. You can also assign them to multiple variables by chaining them: `a=b=c=5` which is the same as saying: `a=5;b=5;c=5`
`+=`
`a += b` is equivalent to `a = a + b`
`-+`
Compound Substract
`a -= b` is equivalent to `a = a - b`
`*=`
Compound Multiply
`a *= b` is equivalent to `a = a * b`
`/+`
Compound Divide
`a /= b` is equivalent to `a = a / b`
`%=`
Compound Modulus
`a %= b` is equivalent to `a = a % b`
`&=`
Compound Concatenation
A way to concatenate strings together `a = "hello "` `a &= "luis"` The result will be `hello luis`
`&`
Concatenation
Concatenates two strings: `"Hola" & space & "Luis"`

## Logical Operators

Logical operators perform logic between values or values, usually denoting a `boolean` result.
Operator
Name
Description
`!,NOT`
Negation
`!true = false` or `a = not true`
`&&,AND`
And
Returns true if both operands are true. `a = b && c`
`||, OR`
Or
Returns true if either operand is true. `a = b`
`XOR`
Exclusive Or
Returns true when either of the operands is true (one is true, and the other is false), but both are not true, and both are not false. `true XOR true = false` `true XOR false = true` `false XOR false = false`
`EQV`
Equivalence
The exact opposite of an exclusive or. Meaning that it will return true when both operands are either true or false. `true EQV true = true` `true EQV false = false` `false EQV false = true`
`IMP`
Implication
A implies B is equivalent to `if a then b`. A imp b is false ONLY if a is true and b is false; else, it returns true always.

## Comparison Operators

Comparison operators are used when comparing two values, expressions, or variables. The return of a comparison is either `true` or `false`.
Operator
Name
Description
`eq,==`
Equality
True if `a eq b` or `a == b`
`neq,` `!=,` `<>`
Not Equal
The opposite of equality: `a neq b, a != b, a <> b`
`===`
Identity
Returns true if the operands are equal in value and in type. `2 === "2" // false` `2 === 2 // true`
`!===`
Negated Identity
Same as the identity operator but negating the result.
`gt,>`
Greater than
If the left operand is greater in value than the right operand
`gte, >=`
Greater than o equal
If the left operand is greater than or equal in value than the right operand
`lt, <`
Less than
If the left operand is less than in value than the right operand
`lte, <=`
Less than or equal
If the left operand is less than or equal in value than the right operand
`contains,ct`
Contains
Returns true if the left operand contains the right one. `'hello' contains 'lo'`
`does not contain, nct`
Negated contains
Returns true if the left operand does NOT contain the right one. `'hello' does not contain 'pio'`

## Ternary Operator

The ternary operator is a conditional operator that works just like an `if-then-else` statement but in shorthand syntax. It has three operands:
condition ? value1 if true : value2 if false
The `condition` must evaluate to a `Boolean` value. If `true` then the `value1` will be used, or else `value2` will be used. You can combine this operator with parenthesis, Elvis operators, etc., to build rich expressions.
result = ( 10 > 0 ) ? true : false
result = animal eq 'dog' ? 'bark' : 'not a dog'
// More complex approach
result = creditScore > 800 ? "Excellent" :
( creditScore > 700 ) ? "Good" :
( creditScore > 600 ) ? "Average" : "Bad"

## Elvis Operator (Null Coalescing)

The Elvis operator is usually referred to as the null coalescing operator. Its name comes from the symbol it represents, which looks like Elivs hair turned sideways: `?:`. If the expression to the operator's left is `null` , then the expression on the right will be evaluated as the result of the expression.
expression ?: defaultValueOrExpression
Here is a simple example:
function process( result ){
writeOutput( result ?: "nothing passed" )
}
process() // produces 'nothing passed'
process( "hello" ) // produces 'hello'
displayName = rc.name ?: 'Anonymous'
event
.getResponse()
.setError( true )
.setData( rc.id ?: "" )
Please note that we have seen inconsistencies in both Adobe and Lucee engines regarding the implementation of this operator. I would avoid using it in Adobe 2018 as it is broken in several cases.

## Function Operators

In CFML, functions can act as operators as well, as you can use the results of the function call as the operands. Function arguments can also act as expressions, and you can even pass more functions into functions as arguments or even return functions from functions. Now that's a fun tongue twister.
results = ucase( "this is text " ) & toString( 12 + 50 )
// I can also pass lambdas or anonymous functions as arguments
results = listener( 2 * 3, (result) => result + 1 )

## Collections Operators

Many operators can work on collection objects like arrays, structs, and queries. So let's start investigating them.

The Safe Navigation operator avoids accessing a key in a structure or a value in an object that does `null` or doesn't exist. Typically when you have a reference to an object, you might need to verify that it exists before accessing the methods or properties of the object. To avoid this, the safe navigation operator will return `null` instead of throwing an exception, like so:
var user = userService.findById( id )
// If user is not found, then this will still work but no exception is thrown.
echo( user?.getSalary() )
s = { name : "luis" }
echo( s.name )
echo( s?.name )

The spread operator allows an iterable object to expand and merge in certain declarations in code. These objects in CFML are mostly arrays and structures. This operator can quickly merge all or parts of an existing array or object into another array or object. This operator is used by leveraging three dots `...` in specific expressions.
var variableName = [ ...myArray ]
var variableName = [].append( myArray )
var mergedObject = { ...obj1, ...obj2 }
mergedObject.append( obj1 ).append( obj2 )
You can accomplish the result of the spread operator with the `append()` member function or traditional function in a very elegant and user-friendly syntax. It also allows you NOT to do chaining but inline expressions.
The Spread syntax also allows an iterable such as an array expression or string, to be expanded in places where zero or more arguments (for function calls) are expected. Here are some examples to help you understand this operator:

#### Function Calls

numbers = [ 1, 2, 3 ]
function sum( x, y, z ){
return x + y + z;
}
// Call the function using the spread operator
results = sum( ...numbers ) // 6
// Ignore the others
numbers = [ 1, 2, 3, 4, 5 ]
results = sum( ...numbers ) // 6

#### Array Definitions

numbers = [ 1, 2, 3 ]
myArray = [ 3, 4, ...numbers ]
myArray2 = [ ...numbers ]
myArray2 = [ ...numbers, 4, 66 ]

#### Struct Definitions

var mergedObject = { ...obj1, ...obj2 }
user1 = { name : "luis", age: 15 }
user2 = { name : "joe", location : "miami" }
mergedUsers = { ...user1, ...user2 }
// What will the output be?
writeDump( mergedUsers )
// { name : "joe" , age : 15, location : "miami" }

### Rest Operator

Only available in ACF 2021+ and for function arguments
The Rest function operator is similar to Spread Operator but behaves oppositely. The spread syntax expands the iterable constructs into individual elements, and the Rest syntax collects and condenses them into a single construct, usually an array. Please note that this operator only works on function arguments as of now.
Imagine I need to create a function that takes in an unlimited number of Identifiers, so I can return all items that have that ID:
function findById( ...ids ){
}
findById( 1 ) // ids is a single value of 1
findById( 1, 23, 34, 456 ) // ids is an array of values
You can also combine them in functions with other arguments:
function findById( entityName, ...ids ){
}
findById( "User", 1 ) // ids is a single value of 1
findById( "Car", 1, 23, 34, 456 ) // ids is an array of values