Blog
By Bruce Silver
(Read Time: 5 Minutes)
The FEEL language has been criticized for not being quite as business-friendly as its originators hoped.
One particular target of this criticism has been FEEL’s use of the value null to mean both a missing value and an execution error. Now DMN 1.6 tries to improve things with the introduction of a new dialect of FEEL called B-FEEL, for “Business-Friendly Expression Language”. The B-FEEL grammar – the formal rules of parsing the language in a compiler – are the same as for regular FEEL, but the semantics – the computed value – of certain expressions involving null or invalid arguments are different, more in line with what most users expect.
Here is a simple example:
In FEEL, the expression “a” = 1 returns null It is an execution error, since you cannot compare a text value to a number. In B-FEEL, it returns false, since the values are clearly not equal. B-FEEL corresponds more closely to business user expectations.
Regular FEEL is not deprecated; it still works. Tools provide a choice as to whether expressions are to be evaluated as FEEL or B-FEEL. n Trisotech Decision Modeler, the choice is made for the model as a whole in two ways.
In the Home ribbon selecting Details/Model
In the Execution ribbon selecting FEEL/Dialect
Both will open the Details panel as per below:
Differences between FEEL and B-FEEL occur in the following types of expressions:
All of the following expressions in FEEL return null but in B-FEEL return false:
“a” = 1 => false
16 > null => false
not(0) => false
X = 4 and X+4 => false
“1” in [0..1] => false
matches(SSN, "[0-9]{3}-[0-9]{2}-[0-9]{4}") => false
(Note: second argument of matches() must be a literal string.)
All of the following expressions in FEEL return null but in B-FEEL return a zero with null or invalid arguments.
decimal(162.623, “2”) => 0
string length(11) => 0
Functions on collections returning a number ignore null and non-number items in the collection:
sum([1,2,null]) => 3
mean([1,2,null]) => 1.5
sum(1,2,”3″) => 3
sum([]) => 0
All of the following expressions in FEEL return null but in B-FEEL return the empty string “”:
substring(“myString”, “S”) => “”
string(null) => “”
All of the following expressions in FEEL return null but in B-FEEL return the default date/time value based on the ISO8601 string value 1970-01-01T00:00:00+00:00, i.e. January 1, 1970, midnight UTC:
date(“2024-06-31”) => date(“1970-01-01”)
The following duration functions in FEEL return null but in B-FEEL return a duration value of zero, such as duration(“PT0S”)
Functions that normally return a list in FEEL and return null with invalid arguments return the empty list [] in B-FEEL:
split(“a,b,c”, 2) => []
The mode() statistical function ignores null or non-number arguments.
The range() function converts a range string to a FEEL range. An invalid argument in FEEL returns null but in B-FEEL returns the empty range (0..0).
The + operator means arithmetic addition when the operands are numbers and string concatenation when they are strings. The – operator means subtraction when the operands are numbers and returns the empty string when they are strings. When operands have different types, however, FEEL often returns null, but B-FEEL converts one of the operand types so that addition or concatenation can proceed normally. Which operand type gets converted is subject to precedence rules, so that the following order is followed:
String conversion. If one operand is a string and the other is not, the non-string operand is converted to a string using B-FEEL and concatenation applies.
Number conversion. Else, If one operand is a number and the other is not, the non-number operand is converted to zero using B-FEEL and arithmetic applies.
Date and time, date, or time. Else, if one operand is a date and time, date, or time and the other is not, the other value is converted to a zero duration using B-FEEL and arithmetic applies.
date(“2024-07-15”) + null => date(“2024-07-15”)
Duration. Else, if one operand is a duration and the other is not, the other value is converted to a zero duration using B-FEEL and arithmetic applies.
If one operand is a number and the other is not, the other is converted to zero.
B-FEEL is brand new, and I admit I have not had much time to apply it in my own work, but here are what I believe will prove to be the main benefits.
The primary motivation for it originally was to meet the common-sense expectations of business users that an expression like
a > 0
returns false, not null, when a is null or, say, a text value.
It certainly does that, but an experienced FEEL modeler might not have the same expectation. In particular, if a is a text value, that implies an error, either in the input data or the decision logic, and a null result indicates that in a way that false does not.
Even experienced modelers will appreciate the simplification of many expressions when values could be null.
For example, suppose a loan application or a tax form includes a list of income items. In DMN that would be a variable incomeItems, a collection of tIncomeItem with a number component value. To find the total income value, in FEEL you would have to write
if incomeItems.value[item!=null] = [] then 0 else sum(incomeItems.value[item!=null])
That’s because the sum() function returns null if its argument is an empty list or includes any null values. B-FEEL simplifies the expression considerably:
sum(incomeItems.value)
In B-FEEL, null items are converted to zero in functions returning a number, so the sum is zero in that case, and it is zero if there are no income items at all. Situations like this occur all the time.
Here is another example. Suppose we have a field totalIncome that we want a Boolean expression testing if is greater than zero. In FEEL that requires something like this to handle the possibility that totalIncome is null:
if totalIncome = null then false else totalIncome>0
In B-FEEL it is simpler:
totalIncome>0
Explanatory statements, including error messages, returned by a decision service typically concatenate fixed text and calculated values. In FEEL you might have something like this:
“The value of your account on ” + string(today()) ” + ” is ” + string(account.value) + “.”
Actually, if there is a possibility that account.value is null, it’s worse:
“The value of your account on ” + string(today()) ” + ” is ” + if account.value=null then “0.” else string(account.value) + “.”
In B-FEEL it is simpler:
“The value of your account on ” + today() + ” is ” + account.value + “.”
You might be concerned that typos and other errors in your expressions might be overlooked if testing does not return null. On the Trisotech platform, they are still reported as warnings, which is quite helpful.
In time, I believe most DMN models will use B-FEEL, but we have to acknowledge that it is not backward-compatible with a lot of existing models, many deployed in production. And it will take time for B-FEEL to make its way into DMN books and training. So the migration will likely be gradual.
Follow Bruce Silver on Method & Style.
Learn how it works
Request DemoConfirm your budget
Request PricingDiscuss your project
Request Meeting