FHIR Chat · Singleton Evaluation of Collections · fhirpath

Stream: fhirpath

Topic: Singleton Evaluation of Collections


view this post on Zulip Aaron Nash (May 01 2020 at 19:00):

I have a question about the rules outlined in http://hl7.org/fhirpath/N1/#singleton-evaluation-of-collections

From the rules I gather "true and 'foo'" evaluates to true. What about "(true | 'foo').allTrue()"? In this case I don't believe 'foo' is an argument of allTrue() so I wouldn't expect it to be treated as true. However, that leaves us with two seemly equivalent expressions that evaluate to different results. Is my interpretation of the rules outlined in Singleton Evaluation of Collections incorrect? Specifically the limitation that the rules only apply "when a collection is passed as an argument to a function or operator that expects a single item as input" which I believe would preclude it's application in the case of allTrue().

view this post on Zulip Paul Lynch (May 01 2020 at 20:37):

Aaron Nash said:

From the rules I gather "true and 'foo'" evaluates to true.

That does not look correct to me. The "and" operator requires both operands to evaluate to true, and 'foo' is not a string that converts to true. Also, string to boolean conversion is explicit, so you would need to call toBoolean() on it.

view this post on Zulip Grahame Grieve (May 01 2020 at 20:39):

right. My engine says "(true and 'foo').empty()"

view this post on Zulip Aaron Nash (May 01 2020 at 20:48):

That seems to contradict the rules under Singleton Evaluation of Collections where it states, "when a collection is passed as an argument to a function or operator that expects a single item as input" then "[...] IF the collection contains a single node AND the expected input type is Boolean THEN The collection evaluates to true"

view this post on Zulip Aaron Nash (May 01 2020 at 20:53):

Example from spec

view this post on Zulip Paul Lynch (May 01 2020 at 20:56):

I see. In "true and 'foo'", the 'foo' is a collection of a single node that is not convertible to Boolean, yet the expected type of "and" is Boolean, so per the spec you quoted, that collection ('foo') should evaluate to true in this context.

view this post on Zulip Paul Lynch (May 01 2020 at 20:58):

@Bryn Rhodes ?

view this post on Zulip Bryn Rhodes (May 02 2020 at 18:23):

Yes, that is the intent of that language in the spec, and the behavior is tested with testPatientHasBirthDate (though there clearly ought to be a test like the one you're suggesting true and 'foo'. The intent was to make it more intuitive to express some constraints, but the spec intentionally does not support converting any singleton value to a true boolean, the behavior only applies when evaluating a collection as input to a boolean-valued argument.

view this post on Zulip John Timm (May 04 2020 at 15:36):

@Bryn Rhodes Are you saying that true and 'foo' should evaluate to true, false or empty?

view this post on Zulip ryan moehrke (May 04 2020 at 16:43):

Should the statement "true and 'foo'" care about the singleton rules at all? Isn't 'foo' a string literal and not a collection? it seems to me that this particular line is a bad way of testing out singleton evaluations..

view this post on Zulip Aaron Nash (May 04 2020 at 16:50):

@John Timm I believe Bryn is saying true and 'foo'should evaluate to true. He responded "yes" to Paul's question that specifically asked if 'foo' should evaluate to true in that context.

view this post on Zulip Ewout Kramer (May 04 2020 at 16:50):

Even 'foo' is a collection, so you can do 'foo'.last() if you wanted. And Patient.name = 'ewout' would compare two collections.

view this post on Zulip Aaron Nash (May 04 2020 at 16:53):

@Bryn Rhodes With your answer in mind, would (true | 'foo').allTrue() evaluate to true? That's less clear to me.

view this post on Zulip John Timm (May 04 2020 at 17:25):

what about (true and 'false')?
'false' is convertable to a Boolean

view this post on Zulip Bryn Rhodes (May 04 2020 at 17:32):

Yes, true and 'foo' would evaluate to true, but (true | 'foo').allTrue() would be an error because 'foo' cannot be converted to a boolean value, and the allTrue() operation expects a collection of boolean values.

view this post on Zulip Aaron Nash (May 04 2020 at 17:55):

And (true | 'foo').where($this)? The documentation for where() states that each element is evaluated "consistent with singleton evaluation of collections behavior." Given that expected type for each element is a boolean and the rules state that if "the collection contains a single node AND the expected input type is Boolean" I would expect that expression to evaluate to true. Though depending how I read the rest of the documentation, I could see that statement being qualified by the requirement that the element is a Boolean prior to following the rules for singleton evaluation of collections.

view this post on Zulip Aaron Nash (May 04 2020 at 17:58):

@John Timm A String does not implicitly convert to a Boolean so (true and 'false') evaluates to true just as (true and 'foo') (see http://hl7.org/fhirpath/N1/#conversion)

view this post on Zulip John Timm (May 04 2020 at 18:28):

@Aaron Nash The spec says:

IF the collection contains a single node AND the node's value can be converted to the expected input type THEN

It doesn't say implicitly or explicitly just "can be converted". @Bryn Rhodes what say you?

view this post on Zulip John Timm (May 04 2020 at 18:33):

@Aaron Nash This is a test case in the suite:

(0).not() = true

It would appear that the expectation is that 0 is converted implicitly to a boolean false. This is, of course, despite what the table says here:
http://hl7.org/fhirpath/N1/#conversion

view this post on Zulip Bryn Rhodes (May 04 2020 at 18:36):

In the Conversion topic, it defines implicit vs explicit as implicit "happens automatically" as opposed to explicit which "require" use of the conversion function. On that read, true and 'false' would indeed be true, but there is room in the wording for Singleton Evaluation of collections to interpret that "can be converted" as either implicitly or explicitly, since it's a different context than just function argument evaluation. That seems to me to be need a clarification, and would lean heavily on what implementations currently do to provide that clarification.

view this post on Zulip John Timm (May 04 2020 at 18:38):

@Bryn Rhodes There are several examples in the test suite that indicate implicit conversion is the expectation. Our implementation currently uses implicit conversion.

view this post on Zulip Ewout Kramer (May 04 2020 at 18:45):

It's implicit in my .NET implementation.

view this post on Zulip Paul Lynch (May 04 2020 at 23:00):

I would find it confusing if the conversion table says the conversion is "explicit" but then there are cases where it happens implicitly.

view this post on Zulip Aaron Nash (May 04 2020 at 23:44):

In addition, allowing a singleton evaluation of a collection to preform "explicit" conversions significantly erodes the language's ability to use its type system to catch user mistakes. Any function that accepts a String would then be able to accept any primitive. That might be desirable in some situations but given the existence of the implicit/explicit conversion table it seems like that was not the original intention when the spec was written.

view this post on Zulip Bryn Rhodes (May 05 2020 at 16:19):

I agree, and can say with confidence that is the intent of defining implicit vs explicit conversions. @Aaron Nash , would you be willing to submit a tracker to request clarification for this item?

view this post on Zulip Aaron Nash (May 05 2020 at 16:22):

@Bryn Rhodes Sure. I'll take care of that this afternoon.

view this post on Zulip Aaron Nash (May 05 2020 at 17:29):

https://jira.hl7.org/browse/FHIR-27033

view this post on Zulip Paul Lynch (Mar 11 2021 at 00:49):

In the R4 tests, there is "(0).not() = true". Is that in error? I did not see mention in the above tracker item about correcting that. Conversion between Integers and Booleans is Explicit, so per the resolution of that tracker item, I would expect that test to return false.

view this post on Zulip Bryn Rhodes (Mar 12 2021 at 00:29):

That's my interpretation of that tracker as well, the implicit conversion to boolean there is not allowed and that causes (0).not() to return false (because the singleton evaluation is effectively an exists test when used in a boolean context).


Last updated: Apr 12 2022 at 19:14 UTC