Skip to content

Fix equality of empty lists ({} = {} -> true) (#1721) - #1793

Closed
c-schuler wants to merge 4 commits into
mainfrom
fix/empty-list-equality
Closed

Fix equality of empty lists ({} = {} -> true) (#1721)#1793
c-schuler wants to merge 4 commits into
mainfrom
fix/empty-list-equality

Conversation

@c-schuler

@c-schuler c-schuler commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Problem

{} = {} returned null instead of true (and {} != {} returned null instead of false). Per the spec, the = operator for lists returns true when the lists "have the same elements by value, in the same order" — two empty lists are vacuously equal.

Root cause

EqualEvaluator.listsEqual had an over-broad guard that returned null whenever either list was empty:

if (!leftIterator.hasNext() || !rightIterator.hasNext()) {
    return null
}

This conflated "empty list" with "null". It was introduced in the Equal/Equivalent refactor (#1668). The existing loop/tail logic already handles empty lists correctly, so the guard was both unnecessary and wrong.

Fix

Removed the guard. Behavior is now:

expression result
{} = {} true
{} != {} false
{null} = {null} true (nulls considered equal
{} = null / null = {} null (null operand)

Null-element handling is unchanged

The removed guard only fired for empty lists (zero elements); lists that contain nulls have hasNext() == true, so they were never affected. The existing element-wise logic continues to implement the spec's two clauses correctly - a null matched against another null is equal, a null against a non-null (or a trailing null on a length mismatch) yields null:

expression result
{1, null} = {1, null} true
{1, null} = {1, 2} null
{1} = {1, null} null
{1} = {1, 2} false

EquivalentEvaluator.listEquivalent has no analogous guard, so this bug was isolated to EqualEvaluator.

Engine test corrections

The engine's own tests asserted the buggy null for {} = {}; updated to match the conformance suite (EqualEmptyListAndEmptyList -> true, NotEqualEmptyAndEmpty -> false):

  • ListOperatorsTest.kt: EqualEmptyListAndEmptyList, NotEqualEmptyAndEmpty.
  • CqlInternalTypeRepresentationSuiteTest.kt: equal({}, EMPTY_LIST) (parameterized over timezones).

Validation

  • Full :engine:jvmTest: 228 tests, 0 failures.
  • CQL Tests conformance: EqualEmptyListAndEmptyList and NotEqualEmptyAndEmpty now pass; no regressions.

Fixes #1721

@c-schuler
c-schuler requested review from antvaset and brynrhodes July 6, 2026 21:22
@c-schuler c-schuler self-assigned this Jul 6, 2026
@c-schuler c-schuler added the bug label Jul 6, 2026
@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown

Related Issues

The following open issues may be related to this PR:

Issue Title Score Matched Terms
#1723 Distinct operation on a list with all nulls does not return a list but a single null 26.5 "null expression", "list null", "return null", "null null", "null instead", operator, instead, returns, return, null, expression, nulls, returned, tests, operators (path), org (path), cql (path), list (path), test (path)
#1794 Point from Interval[null, null] is returning null instead of erroring 24 "per spec", "null expression", "null null", "null instead", result, true, instead, return, bug, spec, null, expression, per, tests, operators (path), org (path), cql (path), test (path)
#1133 ToList is not implemented according to the spec 22.5 "operand null", operator, returns, lists, bug, operand, behavior, element, already, spec, null, logic, expression, value, type (path), java (path), src (path), opencds (path), engine (path), main (path), org (path), cql (path), cqf (path), elm (path), execution (path), list (path), test (path)
#1735 Expression Tuple equivalence on tuples with mismatched number of items does not return false 21.5 "cql tests", "null false", "returns true", operator, true, returns, return, both, false, null, expression, equivalent, tests, value, org (path), cql (path), test (path)
#1763 CqlComparisonOperatorsTest "groupName": "Unit Comparison" have many failures 21 "cql tests", "null true", "false null", true, returns, bug, false, equality, failures, null, expression, either, tests, engine (path), org (path), cql (path), test (path)

Tip: If this PR addresses any of these issues, please link them using Closes #NNN or Refs #NNN in the PR description.

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown

Formatting check succeeded!

@c-schuler

Copy link
Copy Markdown
Contributor Author

Closing this as the cql-tests test is found to be in error: cqframework/cql-tests#129

@c-schuler c-schuler closed this Jul 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Empty list compared to empty list returns null

1 participant