What’s New in DMN 1.4 and 1.5
Blog: Method & Style (Bruce Silver)
One of the great things about the DMN standard is it is continually being updated with new features that make it more powerful and easier to use. As soon as the DMN Revision Task Force (RTF) submits a new version for OMG approval, it immediately begins on the next revision. That approval process, for some reason, is exceptionally slow. While DMN 1.4 was just recently released to the public, DMN 1.5 is already complete and the RTF is working on version 1.6. In this post we’ll outline what’s new in both DMN 1.4 and 1.5.
DMN 1.4
A few new FEEL functions and boxed expressions were added in DMN 1.4, as well as minor changes to the FEEL grammar and examples.
New FEEL Functions
string join()
It is not uncommon to want to concatenate a list of text items into a single string, either delimited or not. That’s what string join() does. It’s one I use a lot. With a single argument, string join() simply concatenates the list items:
- string join([“a”, “b”, “c”]) returns “abc”
With two arguments, the second one provides the delimiter:
- string join([“a”, “b”, “c”], “-“) returns “a-b-c”
- string join([“a”, “b”, “c”], “, “) returns “a, b, c”
context put()
Several new context functions were added, of which the most useful by far is context put(). Before context put(), if you wanted to add a column to a table, you needed to iterate a context BKM with one context entry per column, copying the old values except for the one new value – a lot of work for such a small thing. Context put() makes it simpler.
- context put(myContext, key, value) adds a component with name specified by key and the value specified by value if myContext does not already have a component with the name specified by key. If key is already a component of myContext, context put() simply updates its value.
- In the common use case of adding a column to a table, you just need a literal expression, not a BKM – something like this:
-
for x in myTable return context put(x, newColName, )
- Here x is a row of myTable.
-
Other Context Functions
Also new but not quite as useful are context() and context merge(). Context() takes a list of key-value pairs and creates a context with those as the context entries. Context merge() takes a list of contexts and creates a single context.
now() and today()
A basic principle of DMN is the model should return the same result regardless of when you execute it. The new FEEL functions now() and today() in a DMN model violate that principle, but they are often too convenient to ignore. now() returns the current date and time; today() returns the current date. If you want to be pure about it, you can always execute now() or today() in BPMN and then pass the result to input data in DMN.
New Rounding Functions
DMN1.4 adds a few new functions for rounding numbers needed in financial services. Previously, we could round numbers using decimal(), floor(), and ceiling(). DMN 1.4 adds four more: round up(), round down(), round half up(), round half down(). All the rounding functions have two parameters, number and scale. Scale determines the number of digits following the decimal point following rounding. The differences between the rounding functions are described below:
New Boxed Expressions
Some business users find certain operators confusing when used in complex literal expressions. DMN1.4 accordingly added new boxed expressions to try to make them simpler.
Filter
The filter boxed expression separates the original list from the filter condition. Instead of a literal expression like this:
CustomerTable[LoyaltyStatus = "Gold"]
the filter boxed expression looks like this:
Conditional
The conditional boxed expression is an alternative to if..then..else literal expressions. Instead of a literal expression like this:
if count(Gold Customers) >0 then sum(Gold Customers.CurrentYearPurchaseAmount) else 0
the conditional boxed expression looks like this:
Iterator
The iterator boxed expression is an alternative to for..in..return, some..in..satisfies, or every..in..satisfies operators in literal expressions. Instead of a literal expression like this:
for customer in Gold Customers return getMedianPurchaseAmount(customer)
the iterator boxed expression looks like this:
DRD Changes
In the DRD, decisions and input data that are collections are now marked with three vertical bars. This is actually convenient in spotting errors in the element type assignments.
DMN 1.5
Most of the improvements in DMN 1.5 were minor and technical in nature. Here are the most significant ones.
Import into the Default Namespace
Prior to DMN 1.5, importing elements from another DMN model required assigning them a namespace prefix to avoid name and type conflicts with the importing model namespace. Trisotech Decision Modeler has always supported this with its Include feature, but for a long time has also supported an alternative, more convenient import mechanism using the Digital Enterprise Graph. DMN 1.5 now makes a key feature of that mechanism – importing directly into the importing model namespace – officially part of the standard. Doing it this way does not require prefixing the imported elements, and effectively allows a complex model to be assembled from multiple model files, all within the same namespace. When a namespace for the imported elements is not provided, DMN 1.5 assigns them to the importing model namespace. When there is a name or type conflict between the imported elements and the importing model, the original importing model names and types are preserved.
Allowed Values and Unary Tests
Prior to DMN 1.5, item definitions could apply simple constraints to variables, such as a numeric range or an enumerated list of allowed values. These constraints were roughly equivalent to the simple unary tests defining allowed expressions in decision table condition cells. Many decision tables, however, require generalized unary tests – effectively any FEEL Boolean expression – in a condition cell. DMN 1.5 now aligns the specification of item definition allowed values with generalized unary tests. For example, now it is possible to define some variable as an integer, a number with the constraint value=floor(value), something impossible in earlier versions.
Trisotech Decision Modeler takes advantage of this in its new type checking feature, discussed in a previous post.
list replace()
Prior to DMN 1.5, “poking” a new value somewhere in a large data table was cumbersome. The new list replace() FEEL function makes it a lot easier. list replace() does what its name implies: replaces an item in a list – for example, a row in a table – with a new item, without changing any of the other list items. There are two forms of the list replace() function.
- list replace(list, position, newItem) is straightforward: First you need to find the position in the list of the item you want to replace, and the function replaces the item originally in that position with newItem.
- list replace(list, match, newItem) is more powerful. The second parameter, match, is not a value but a function, similar to the precedes parameter in the sort() function. match() is a Boolean function with parameters item, meaning any item in the list, and possibly others, including newItem. Any list items for which match() is true are replaced by newItem. As in the sort() function, match is most conveniently modeled as an anonymous function, inline in list replace(), using the keyword function. For example:
-
list replace([2,4,7,8], function(item, newItem) item<newItem, 5)
- replaces all list items less than 5 with the value 5, or the list [5,5,7,8]
-
In the Low-Code Business Automation course, we use list replace() to modify a cloud datastore holding the accrued vacation days for each employee, potentially a very large table. After updating an employee’s accrued vacation days value following a vacation request, we use context put() – described above in the DMN 1.4 section – to generate the new table row, and list replace() to replace the employee’s record in the datastore with the new row.
Scientific Notation
The FEEL grammar was extended to allow specification of number values in scientific notation. For example, the value 1.2e3 is equivalent to 1.2*10**3, or 1200.
As you can see, while its basic functionality is little changed, DMN is a “living language,” continually made more powerful and easier to use as new use cases arise. Want to learn more about how it works? Our DMN Method and Style training is comprehensive, covering the latest features and including 60-day use of the Trisotech Decision Modeler and post-class certification. Check it out!