Article authors: @Yeser Amer, @Athira C and @Chinchu P Shaji
We’re delighted to announce support for the DMN 1.6 specification in BAMOE 9.3.0, reinforcing IBM’s roadmap and vision to provide end users with the latest features and experiences in DMN.
The official DMN 1.6 specification, including a comprehensive description of changes and new features, is available on the OMG DMN specification site1. In this article, we highlight the most notable changes that impact DMN end users.
1. A new expression language: B-FEEL
B-FEEL (Business Friendly Enough Expression Language) shares the same grammar as FEEL but alters the semantics to be friendlier to a business audience.
In FEEL, the null value is used to represent both missing data and an execution error.
In B-FEEL, null is used only to represent missing data. All operations and built-in functions that return null in FEEL when an error occurs have their semantics modified in B-FEEL to return a non-null value.
FEEL remains the default expression language in DMN 1.6.
To switch to the B-FEEL, manually update the expression language in the Global properties panel:

In detail, the new B-FEEL expression language differs from FEEL in the following points:
-
Operator and built-in functions returning a boolean
Removing null as an error from the result of operators and built-in functions for boolean values makes B-FEEL a two-value logic (true and false) compared to the three-value logic of FEEL (true, false, and null).
In B-FEEL, boolean operators ( =, <=, <, >, >=, not(), and, or, in, between ) always return a true or false result (never null) even when incompatible types are used in their expression.
In B-FEEL, an incompatible type in a boolean expression is considered false, except for the not equal (!=) where it is considered true.
An example:
|
Expression
|
FEEL
|
B-FEEL
|
|
"a" = 1
|
null
|
false
|
-
Built-in functions returning a number
Several FEEL built-in functions return a numeric result. In B-FEEL, those functions’ semantics are modified to return 0 everywhere FEEL would return null for them.
In addition, the list functions that return a number (mean(), median(), product(), stddev(), sum()), except count(), ignore non-numeric parameters passed in their input list in B-FEEL.
An example:
|
Expression
|
FEEL
|
B-FEEL
|
|
decimal("a", 0)
|
null
|
0
|
-
Built-in functions returning a string
Several FEEL built-in functions return a string result. Those methods’ semantics in B-FEEL are modified to return an empty string (“”) everywhere FEEL would return null for them.
An example:
|
Expression
|
FEEL
|
B-FEEL
|
|
lower case(12)
|
null
|
“”
|
-
Built-in functions returning a date and time, date and time
Several FEEL built-in functions return a date and time, date, or time result. In B-FEEL, those functions’ semantics are modified to return January 1st of the year 1970 (1970-01-01T00:00:00+00:00) value (epoch) everywhere FEEL would return null for them.
The default values are based on the return type:
|
Type
|
Default Value
|
|
Date and time
|
date and time(“1970-01-01T00:00:00+00:00”)
|
|
Date
|
date(“1970-01-01”)
|
|
Time
|
time(“00:00:00+00:00”)
|
Some examples:
|
Expression
|
FEEL
|
B-FEEL
|
|
time("a")
|
null
|
time(“00:00:00+00:00”)
|
|
date(null)
|
null
|
date(“1970-01-01”)
|
|
date an time(true)
|
null
|
date and time(“1970-01-01T00:00:00+00:00”)
|
-
Built-in functions returning a duration
Several FEEL built-in functions return a duration result. In B-FEEL, those functions’ semantics are modified to return a duration of 0 months (years and months durations) or 0 seconds (days and time duration) everywhere FEEL would return null for them.
An example:
|
Expression
|
FEEL
|
B-FEEL
|
|
duration("a") or years and months duration(null, null)
|
null
|
duration(“P0M”)
|
-
Built-in functions returning a collection
Several FEEL built-in functions return collection results. In B-FEEL, those functions’ semantics are modified to return an empty collection everywhere FEEL would return null for them.
The mode function additionally ignores non-numeric parameters passed in their input list in B-FEEL.
Some examples:
|
Expression
|
FEEL
|
B-FEEL
|
|
split("abc", 22)
|
null
|
[]
|
|
mode([null,null,null, 1, 1,2])
|
null
|
[1]
|
-
Built-in functions returning a range
The FEEL built-in function range() returns a range result. In B-FEEL, that function’s semantics is modified to return an empty range that does not match anything ( (0..0) ), where in FEEL it would return null.
An example:
|
Expression
|
FEEL
|
B-FEEL
|
|
range("x")
|
null
|
range(“(0..0)”)
|
-
Semantics of addition and subtraction
In B-FEEL, the semantics of addition and subtraction are modified when the types of e1 and e2 do not match.
The following rules are added :
|
If type(e1) or type(e2) is …
|
e1 + e2 / e1 - e2
|
|
string
|
The non-string value is converted to a string using the string B-FEEL function and the general semantics of addition and subtraction apply. Subtraction returns an empty string.
|
|
number
|
The non-number value is converted to a number using the number B-FEEL function and the general semantics of addition and subtraction apply.
|
|
date and time
|
The non-date and time value is converted to a duration using the duration B-FEEL function and the general semantics of addition and subtraction apply.
|
|
date
|
The non-date value is converted to a duration using the duration B-FEEL function and the general semantics of addition and subtraction apply.
|
|
time
|
The non-time value is converted to a duration using the duration B-FEEL function and the general semantics of addition and subtraction apply.
|
|
years and months duration
|
The non-years and months duration value is converted to a duration using the duration B-FEEL function and the general semantics of addition and subtraction apply.
|
|
days and time duration
|
The non-days and time duration value is converted to a duration using the duration B-FEEL function and General semantics of addition and subtraction apply.
|
Some examples:
|
Expression
|
FEEL
|
B-FEEL
|
|
"Today is " + today()
|
null
|
"Today is 2020-01-01"
|
|
"The result is: " + 1
|
null
|
"The result is: 1"
|
-
Semantics of multiplication and division
In B-FEEL, the semantics of multiplication and division are modified when the types of e1 and e2 do not match.
The following rules are added :
|
If type(e1) or type(e2) is …
|
e1 * e2 and e1 / e2
|
|
number
|
The non-number type is converted to a number using the number B-FEEL function and the general semantics of multiplication and division apply.
|
|
years and months duration
|
The non-years and months duration type is converted to a number using the number B-FEEL function and general semantics of multiplication and division applies.
|
|
days and time duration
|
The non-days and time duration type is converted to a number using the number B-FEEL function and general semantics of multiplication and division apply.
|
Some examples:
|
Expression
|
FEEL
|
B-FEEL
|
|
22 * "a"
|
null
|
0
|
|
null / 22
|
null
|
0
|
|
duration("P1Y") * null
|
null
|
duration(“P0M”)
|
-
Semantics of exponentiation
The FEEL semantics of exponentiation are used and B-FEEL further specifies that each operand is converted to a number using the number B-FEEL function.
2. Simplified InputData Assignment Across Nested Imports
DMN 1.6 introduces a key enhancement that simplifies how InputData values are assigned across models with nested or transitive imports during model evaluation. In such cases, the value is now assigned only once. This means that even if multiple models refer to the same input data through different import paths, they will consistently share the same value.
Previously, when an InputData (like Person name) was imported multiple times through different paths (Model B imports Model A, Model C imports Model A), each import path required a separate, fully qualified assignment:
Model B.Model A.Person name = "value"
Model C.Model A.Person name = "value"
With DMN 1.6, this has been streamlined. Now, the same InputData can be assigned once, using its namespace, and that value is automatically propagated across all import paths:
Person name = "value"
This change promotes cleaner model definitions and reduces redundancy, especially in complex import hierarchies. The system ensures that all references to that input data—regardless of how deeply nested or imported—receive the same value.
Importantly, the previous behavior is still supported. Users can continue assigning values using fully qualified paths if needed. This ensures:
• Existing models remain functional without modification
• Users have the flexibility to choose the assignment style that best fits their use case
3. Configurable Error Handling Modes – Lenient and Strict
In this version, two distinct modes for managing errors during decision model evaluation have been introduced:
-
lenient: In this mode, if an error is detected during model evaluation, it is stored and the execution continues. If other errors occur, all of them are collected. At the end of the evaluation, all the errors will be reported.
-
strict: In this mode, the model evaluation halts upon detecting the first error, which will be the only reported error.
The default error handling mode is lenient.
This enhancement applies consistently across all DMN expressions, including FEEL expressions and built-in functions.
To change the error handling mode during model evaluation, go to the Run menu and switch to the chosen mode.
4. Deprecated type `time` with timezone :
In DMN 1.6, IANA Time Zone identifiers in time literals have been officially deprecated. This change was introduced to improve consistency and reduce ambiguity in time-only representations.
In detail:
-
Time literals using the format: "HH:mm:ss@Zone" (e.g., "14:30:00@Asia/Kolkata") are now deprecated.
-
Date and time literals using IANA zones are not deprecated.
The recommended approach is to use the FEEL function: date and time(date, time, timezone) instead of relying on implicit parsing of time strings with zones.
The effects of this deprecation are:
-
No breaking changes. Previous usage of the time with timezone is still working.
-
A warning when deprecated time literals are used will be thrown. The warning given in the current implementation is: Usage of 'time' with a timezone is deprecated in DMN 1.6. This usage may be removed in future versions.
-
Encourage migration to FEEL-compliant expressions.
5. New version of `date and time` conversion function
As part of the deprecation of the time type with a timezone previously described, DMN now includes a new conversion function:
date and time(date, time, timezone)
• date: A date or date-time value
• time: A time value without timezone
• timezone: A string representing either a timezone offset (e.g. "Z", "+05:30") or an IANA zone identifier (e.g. "America/Costa_Rica")
This function returns a full date-time value by combining the provided date and time, and applying the specified timezone.
|
|
|
|
date and time(date("2024-12-24"), time("23:59:00"), "Z")
|
2024-12-24T23:59:00Z
|
|
date and time(date("2024-12-24"), time("23:59:00"), "America/Costa_Rica")
|
2024-12-24T23:59:00@America/Costa_Rica
|
6. New single-parameter number() function :
A new number() function is now available in FEEL. Its main scope is to convert a string-type input to a number type, if compatible.
-
If input is a number, it returns the number unchanged.
Example: number(10) = 10
-
If input is a String, it attempts to parse it into a numeric value.
7. New "value" property for types `date`, `date and time`, `years and months duration`, `days and time duration`
A new value property is defined in the following types: date, date and time, years and months duration, and days and time duration.
The actual returned value depends on the field's type. In details:
-
date: Converts a calendar date to a date time value in which the time of day is UTC midnight (00:00:00).
Example: date(2025, 7, 3).value → BigDecimal.valueOf(1751500800)
-
time: Converts a time of day to be represented as the number of seconds since midnight.
Example: time("01:01:01").value → BigDecimal.valueOf(3661)
8. New descendant operator
A descendant operator has been introduced to enhance the expressiveness of FEEL when working with nested contexts. This operator allows for recursively access to all values associated with a given property name, regardless of how deeply nested they are within a context structure.
For example, given the context:
{ a: { b: { b: 1 } } }
Using the descendant operator to access b:
{ a: { b: { b: 1 } } }...b
This expression returns:
[ { b: 1 }, 1 ]
This means it collects all instances of the key b found at any level of nesting and returns them as a list. This is particularly useful for querying deeply structured data without needing to explicitly traverse each level.
9. Automatic type conversion from decimal to integer
DMN 1.6 introduces a new type conversion rule that enables automatic conversion from decimal numbers to integers in integer-required contexts. This enhancement ensures consistent behavior across decision models where integer values are expected, even if the input is a decimal.
This conversion is not rounded—the decimal portion is simply truncated, preserving the integer part of the number.
The following examples illustrate how the new type conversion behaves when applied in integer-required contexts.
-
Decimal input: 42.99999 → 42
-
Integer input: 42 → 42
-
Long Inputs: 423L → 423
-
Non-Numeric Input: 123" → No conversion applied
-
Null Input: null → No conversion applied
10. Single-parameter version of all rounding functions
DMN 1.6 introduces single-parameter versions of all rounding functions in FEEL. These new variants simplify usage by assuming a default scale of 0, delivering more intuitive and streamlined rounding logic and aligning FEEL functions with real-world expectations and simplifying decision logic for modellers.
|
Function Name
|
Example Input
|
Expected Output
|
|
round up(x)
|
round up(5.5)
|
6
|
|
round down(x)
|
round down(5.5)
|
5
|
|
round half up(x)
|
round half up(5.5)
|
6
|
|
round half down(x)
|
round half down(5.5)
|
5
|
References:
[1] https://www.omg.org/spec/DMN