Hello, again.
This is a strange one.... and I'm on version 24.1.281.0
I have two expression rules... one generates some error messages (or none) and the other deals with the errors. However, in the scenario where the first expression rule generates no errors, the second one still thinks there are errors.
Expression 1: (called SH_ErrorGenerator)
a!localVariables( local!stringArray: {"a", "b"}, local!error1: "", /* value from another expression rule normally */ local!error2: "", /* value from another expression rule normally */ local!error3: {""}, /* value from another expression rule normally */ local!errors: { local!error1, local!error2, local!error3 }, local!allErrors: cast( /* make sure this is list of string not list of variant */ typeof(local!stringArray), reject(a!isNullOrEmpty, a!flatten(local!errors)) ), local!anyErrors: and(not(isnull(local!allErrors)), length(local!allErrors) > 0), { errors: local!allErrors, anyErrors: local!anyErrors } )
Expression 2:
a!localVariables( local!result: rule!SH_ErrorGenerator(), local!errors: local!result.errors, local!anyErrors: and(not(isnull(local!errors)), length(local!errors) > 0), local!anyErrors )
Here is the result I see.
result.anyErrors (calculated by SH_ErrorGenerator) is false (as it should be), but local!anyErrors (calculated by second rule) says true. And even the local variables screen says there are 0 items in the array.
Any idea what's going on here?
Thank you.
Discussion posts and replies are publicly visible
A small tweak shows the second expression sees the array as having 1 element.
a!localVariables( local!result: rule!SH_ErrorGenerator(), local!errors: local!result.errors, local!anyErrors: and(not(isnull(local!errors)), length(local!errors) > 0), { a: local!anyErrors, b: length(local!errors) } )
But, of course, you cannot actually index that item.
a!localVariables( local!result: rule!SH_ErrorGenerator(), local!errors: local!result.errors, local!anyErrors: and(not(isnull(local!errors)), length(local!errors) > 0), { a: local!anyErrors, b: length(local!errors), c: local!errors[1] } )
I’ve tried to replicate your case, and it seems that when you’re indexing the value “local!result.error”, it’s returning a list of variants. That’s why you’re getting the error you mentioned.
Actually, your scenario does not faithfully represent my code above. You are, indeed, using an array of variant by specifying {} without any qualification. I explicitly cast my data to List<string> (see first code segment above).
I don't think this will repro without using 2 expression rules. As I showed in my example, within the first expression rule, it does, rightly, know the array is empty. It's not until it is returned to the calling expression rule that the weirdness ensues.
Appian treats lists with empty strings as having length, but they cannot be indexed.Use a!isNullOrEmpty() to check for real errors instead of length().
When you use index() or dot notation, the value returned is a variant. This can produce a different result when you use the length() function.
To resolve this issue, create a map instead of a dictionary, because values stored in maps are not wrapped in a variant.
Additionally, according to the Appian documentation:When you pass an empty array to the isnull() function, it returns false. To check whether an empty list is null, use the a!isNullOrEmpty() function instead.
The expression for local!anyErrors in expression 2 checks if error is not null as well as its length. Though the local!errors is having 0 items yet as the function length("") returns 1. So length will return true. Similarly behavior of isnull() can be understood from below.
not(isnull({""})) returns truenot(isnull("")) returns false
length("") /*returns true*/ not(isnull({""})) /*returns true with a List of empty string*/ not(isnull("")) /*returns false with empty string*/
Given the behavior and working of isnull() and length() the value for local!anyErrors in expression 2 seems fine. To properly check and correct the behavior as per your requirement I suggest you to either replace the local!anyErrors definition with a!isNotNullOrEmpty(local!errors) or simply use local!result.anyErrors.
local!anyErrors: a!isNotNullOrEmpty(local!errors) or, local!anyErrors: local!result.anyErrors /* Either of these*/
In this blog post, I try to cover how to check for empty data.
https://appian.rocks/2022/10/17/the-magic-of-null-checking/
I'm not looking for a string to be empty.... I'm looking to see if an array is empty. Why would length(someArray) be 1 if there are no items in the array? That doesn't make any sense.
And yet, within SH_ErrorGenertor length() did return 0. Why does it sometimes return 0 and sometime return 1 for the same value?
You are correct in that isNullOrEmpty does return true in this case.