Updated type conversion contexts misses some scenarios and need to be more encompassing
-
Key: DMN17-71
-
Status: open
-
Source: Montera Pty Ltd ( Greg McCreath)
-
Summary:
The new-for-1.5 text in "10.3.2.9.4 Type conversions" is a welcome addition, but many type safety / conversion scenarios remain undefined in behaviour.
The undefined behaviour surrounds the use of explicit spec-supported typeRefs not covered by the new text. Indeed, I think the contexts under which type conversions are made can be simply defined and made broader in scope.
In short, TLDR: "any element with an explicit typeRef SHALL be subject to conversion". I'll elaborate on this more at the end.
The current definition is relatively narrow and perhaps focuses on how a human interacting with a DMN UI may use DMN. It may not always be humans creating DMN models ..
The spec support explicit typeRefs at many places. Here are some examples of conversions not covered but the new spec text:
- example: inputData typeRef
```
<inputData name="input_001" id="_input_001">
<variable name="input_001" typeRef="string"/>
</inputData>
```Despite the explicit typeRef, the spec does not mandate type conversion on value assignment to an inputData. It refers to "DRG element's logic".
- example: a boxed list that types some or all elements
A boxed list could be used as a typed tuple. The typing of a list is for all elements of the list so therefore is not suitable here. The individual elements can be typed so a typed tuple could be:
```
<list>
<literalExpression typeRef="string"><text>someStringFunction()</text></literalExpression>
<literalExpression typeRef="number"><text>someOtherFunctionThatReturnsString()</text></literalExpression>
</list>
```The list elements should be subject to conversion with element 2 being null as it has an explicit typeRef, but a value being bound to it does not conform. At this time, the spec does not mandate type conversion on 'inner' elements of boxed expressions - just on the final DRG return type as it is bound to a variable in the global scope.
The same could apply for data-type conversions such as a singleton list:
```
<list>
<literalExpression typeRef="string"><text>someStringFunction()</text></literalExpression>
<literalExpression typeRef="number"><text>[123]</text></literalExpression>
</list>
```The value of the second element should be coerced to just 123. I think implicitly, this is what we would expect, but the spec leaves this undefined.
- example: a typed context entry:
```
<contextEntry>
<variable typeRef="number" name="foo"/>
<literalExpression>
<text>someFunctionThatReturnsAString()</text>
</literalExpression>
</contextEntry>
```The context entry (informationItem) typeRef specifies a number, but a string value is being bound to it - it should be null. The spec does not cover this.
- example: An expression inside the logic of a BKM as such:
```
<businessKnowledgeModel name="bkm_001" id="_bkm_001">
<variable name="bkm_001"/>
<encapsulatedLogic>
<formalParameter name="arg1"/>
<literalExpression typeRef="number">
<text>someFunctionThatReturnsString(arg1)</text>
</literalExpression>
</encapsulatedLogic>
</businessKnowledgeModel>
```In this case, neither the BKM nor the encapsulatedLogic is typed, but the expression of the logic is (or it could also be any nested boxed expression contained with it - you get the idea). With the above BKM example, the function invocation result should be null - the expression type is for number, but it calls something that ends up returning a string.
With might also expect a singleton list to be converted. I think this what we would expect, but, as I read it, this is outside the spec.
- example: An BKM typeRef defines an outputTypeRef.
```
<itemDefinition name="tMyFuncType">
<functionItem outputTypeRef="number">
<parameters name="arg1"/>
</functionItem>
</itemDefinition><businessKnowledgeModel name="bkm_001" id="_bkm_001">
<variable name="bkm_001" typeRef="tMyFuncType"/>
<encapsulatedLogic>
<formalParameter name="arg1"/>
<literalExpression typeRef="number">
<text>someFunctionThatReturnsString(arg1)</text>
</literalExpression>
</encapsulatedLogic>
</businessKnowledgeModel>
```The above BKM has a (functionType) typeRef. The BKM satisfies that typeRef. However, runtime invocations may not satisfy the functionItem return type.
Strictly speaking, when the BKM "DRG Element’s logic" (function) is bound to the variable "bkm_001" it does indeed match the typeRef expectations of the functionType - the informationItem variable of a BKM holds a function, not the return value of an invocation. Currently, the spec says the variable binding is subject to conversion. But, the spec does not cover the type expectations of actually _invoking the BKM. The outputTypeRef specifies a number, but an encapsulatedLogic expression may provide a string.
Again, I think implicitly this is what we would expect - but it is undefined.
- Where should conversion occur?
The 1.5 spec text explicitly defines where conversions can occur in section "10.3.2.9.4 Type conversions" paragraph "There are several kinds of contexts in which conversions may occur".
- filter contexts. Fair enough. No change required
- Invocation parameters - this is really binding a value to a typed InformationItem
- DRG Element logic result bound to variable. This is also binding a value to a type InformationItem.
As you can see from the above, this needs to be broadened and made more complete. I believe conversions should occur at all places the spec supports a typeRef.
The spec model defines typeRefs for the following:
- all expressions, except for UnaryTests
- informationItems
- itemDefinitions, including their "itemComponent"s as well as the (informationItem) parameters of functionItems and the "outputTypeRef" of functionItems
- the outputClauses of decisions
- the iterators of for/some/every boxed expressions
I suggest amending the "There are several kinds of contexts in which conversions may occur" paragraphs text to the following.
- Filter context (10.3.2.5) in which a filter expression is present. The expression to be filtered is subject to implicit conversion to singleton list.
- Any DMN model element that has an explicit typeRef SHALL be subject to conversion. For elements that may have a value bound to them such as all InformationItems, iterators of boxed expressions, and the result values of outputClauses of decisions the conversion takes place at the moment the value is bound. InformationItems includes such elements as DRG Element variable bindings (including inputData), function/invokable/invocation parameter bindings, context entry values, and relation columns.
- if any expression has a typeRef, then the result value of the expression SHALL be subject to conversion against the expression typeRef. A single exception to this is UnaryTests expressions which do not use typeRef. Refer 7.3.2 UnaryTests Metamodel.
- invokable elements such as a FunctionDefinition or BusinessKnowledgeModel or DecisionService that have a typeRef (which must be a function type), and that typeRef function type has an "outputTypeRef", then additionally, the result value of invocation SHALL be subject to conversion against that outputTypeRef.
Basically, - if is has an associated typeRef - then it SHALL be subject to type conversion including singleton lists, conforms to, date vs datetime.
-
Reported: DMN 1.5 — Mon, 19 Aug 2024 01:57 GMT
-
Updated: Wed, 4 Sep 2024 14:05 GMT