Operators

Operators combine values into new values. Most, like arithmetic and comparison operators, work the same way they do in other languages. Two operators are specific to WEL:

  • The pipeline: >> turns a multi-step transformation into a single line that reads top to bottom.
  • The fallbacks: | and |? supply a default value instead of a nested conditional.

_ is the input your expression receives in these examples. Refer to Input variables for more information.

FEATURE AVAILABILITY

WEL is currently available to select customers. Contact your Customer Success Representative to confirm whether it is available in your workspace.

Precedence

The following table lists operators by precedence. Operators higher in the table run before ones lower in it, regardless of where each appears in the expression. Parentheses (()) override precedence order. Wrap part of an expression in parentheses to evaluate it first.

PrecedenceOperatorsMeaning
1. ()Field access, function call
2! not -Unary prefix
3^Power
4* / %Multiply, divide, modulo
5+ -Add, subtract
6++ >> | |?Concatenate, pipe, fallback, try-fallback
7== != < > <= >= inComparison and containment
8andLogical and
9orLogical or

Arithmetic

+ - * / % ^ work on Integer, Float, and Decimal.

OperationFormulaResult
+: Add1 + 2.53.5
-: Subtract5 - 23
*: Multiply4 * 312
/: Divide10 / 33
%: Modulo (remainder)10 % 31
^: Power (exponent)2 ^ 101024

INTEGER DIVISION TRUNCATES

Dividing two Integer values truncates the result. Make one side a Float or a Decimal for a fractional result, and use a Decimal for money. For example:

FormulaResult
10 / 33
10.0 / 33.3333333333333335

Dividing by zero raises E200 rather than producing infinity.

Decimal and Float can't mix. Refer to Data types for which types support arithmetic.

Dates and durations

Operators also work on temporal data types. Add an Integer to a PlainDate to add days, subtract two dates to return the number of days between them, and subtract two instants to return a Duration. Use advance_date or add_months instead for calendar arithmetic where the answer depends on month lengths.

OperationFormulaResult
+: Add days to a datePlainDate('2026-03-15') + 102026-03-25
-: Subtract two dates (day count)PlainDate('2026-03-15') - PlainDate('2026-01-01')73
+: Add a duration to an instantDateTime('2026-01-01T10:00:00Z') + Duration('PT2H')2026-01-01T12:00:00Z
-: Subtract two instants (duration)DateTime('2026-03-01T00:00:00Z') - DateTime('2026-01-01T00:00:00Z')PT1416H

Concatenation

++ joins two values of the same type.

OperationFormulaResult
++: Join two strings'SO-' ++ '1001'SO-1001
++: Join two lists[1, 2] ++ [3][1, 2, 3]

Mixing types raises E101. 'x' ++ 1 is an error, not x1. Convert with String(...), or use an f-string, which converts as it interpolates.

Pipeline operator

>> passes the value on its left as the first argument to the function on its right.

OperationFormulaResult
>>: Pipe a value into a function'acme' >> upperACME

Pipelines read left to right, in the order the steps run. In the following examples lower runs first, then trim, then upper:

text
_.email >> lower >> trim >> upper

Nested calls can achieve the same result as pipelines, but they force you to read the transformation inside-out:

text
upper(trim(lower(_.email)))

This is especially important with lambdas, where nesting quickly becomes unreadable:

Fallbacks

The fallback operators solve different problems:

Null value fallback

| handles null values.

OperationFormulaResult
|: Use a default value when nullnull | 'default'default

presence reports every kind of absence as null so one fallback operator (| ) catches them all, including empty strings, whitespace-only strings, empty lists, and empty maps.

text
presence(_.display_name) | 'Unknown'

Error fallback

|? catches errors.

OperationFormulaResult
|?: Use a default value when the expression raises a catchable error1 / 0 |? 'error'error

Reading a field that doesn't exist raises E104 rather than producing null, so | won't catch it and |? will:

text
_.customer.nickname |? 'none'

Refer to Error codes for which errors are catchable.

A FALLBACK IS A DECISION, NOT A FIX

|? 0 on a currency field means a malformed amount silently becomes zero, and the job reports success. That is sometimes right and sometimes an invoice that quietly goes out wrong.

Use a fallback when the absence is expected and the default is genuinely correct. Let the error propagate when it isn't. A failed job is visible, and a wrong number isn't.

Comparison

== != < > <= >= compare two values.

OperationFormulaResult
==: Equal1 == 1.0true
!=: Not equal1 != 2true
<: Less than1 < 2true
>: Greater than2 > 1true
<=: Less than or equal2 <= 2true
>=: Greater than or equal2 >= 3false

Numeric comparison is by value, so an Integer and a Float holding the same number are equal.

Text that looks identical isn't always equal, because the same characters can be stored more than one way. Use unicode_compare to compare text from two different systems.

Containment

in tests whether a value is an element of a list.

OperationFormulaResult
in: Test list membership2 in [1, 2, 3]true

in is list-only. Use one of the following alternatives for other types:

  • Substring: Use contains?. 'WID' in 'WID-1' raises E101.
  • Map key: Use has_key?. 'a' in {a: 1} raises E101.

Logic

and, or, and not are spelled as words.

OperationFormulaResult
and: Logical and5 > 3 and 2 < 1false
or: Logical or5 > 3 or 2 < 1true
not: Logical negationnot truefalse

Conditionals

if ... then ... else ... is an expression. It produces a value, so it can go anywhere a value can.

OperationFormulaResult
if...then...else: Conditional expressionif 5 > 3 then 'yes' else 'no'yes

The following example shows a conditional inside a map:

text
{
  tier: if _.total > 1000 then 'gold' else 'standard'
}

Last updated: