Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clarify homogeneous equality on lists and maps #128

Merged
merged 2 commits into from
Jun 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions doc/langdef.md
Original file line number Diff line number Diff line change
Expand Up @@ -783,6 +783,49 @@ All predefined operators, functions and constants are listed in the table below.
For each symbol, the available overloads are listed. Operator symbols use a
notation like `_+_` where `_` is a placeholder for an argument.

### Equality and Ordering

Equality (`_==_`) and inequality (`_!=_`) are defined for all types. Inequality
is the logical negation of equality, i.e. `e1 != e2` is the same as `!(e1 ==
e2)` for all expressions `e1` and `e2`.

Equality and inequality are homogeneous; comparing values of different runtime
types results in a runtime error. Thus `2 == 3` is false, but `2 == 2.0` is an
error.

For `double`, all not-a-number (`NaN`) values compare equal. This is different
than the usual semantics of floating-point numbers, but it is more consistent
with the usual expectations of reflexivity, and is more compatible with the
usual notions of equality on protocol buffers.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, why not do the 'right' thing and represent 'not a number' by the existing 'not a value'/falsum/bottom concept in CEL, i.e. an error. I believe this is how CEL fixes integer overflows. You could even just make it so this only pops up when performing operations with NaN, so NaN itself is still observable from within the expression.

Copy link
Contributor

@Alfus Alfus Jun 22, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, what is:

  • NaN < 0.0
  • NaN <= NaN
  • 0 > -0


Lists are unequal if their lengths are different. Otherwise, for lists `a` and
`b` with length `N`, `a == b` is equivalent to

```
a[0] == b[0] && a[1] == b[1] && ... && a[N-1] == b[N-1]
```

Maps are unequal if their key sets are different, otherwise for maps `a` and
`b` with keyset `k1, k2, ..., kN`, `a == b` is equivalent to

```
a[k1] == b[k1] && a[k2] == b[k2] && ... && a[kN] == b[kN]
```

So for equality of both lists and maps this means:

- if the list lengths / map key sets are different, the result is false;
- if one or more element comparisons is false, the result is false;
- if all element comparisons are true, the result is true;
- otherwise the result is an error.

Ordering operators are defined for `int`, `uint`, `double`, `string`, `bytes`,
`bool`, as well as `timestamp` and `duration`. Strings obey lexicographic
ordering of the code points, and bytes obey lexicographic ordering of the byte
values. The ordering operators obey the usual algebraic properties, i.e. `e1 <=
e2` gives the same result as `!(e1 > e2)` as well as `(e1 < e2) || (e1 == e2)`
when the expressions involved do not have side effects.

### Timezones

Timezones are expressed in the following grammar:
Expand Down
24 changes: 23 additions & 1 deletion tests/simple/testdata/comparisons.textproto
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: "comparisons"
description: "Tests for boolean-valued functions and operators."
section {
name: "eq_literal"
description: "Literals comparison on _=_"
description: "Literals comparison on _==_"
test {
name: "eq_int"
expr: "1 == 1"
Expand Down Expand Up @@ -33,6 +33,12 @@ section {
expr: "-1.0 == 1.0"
value: { bool_value: false }
}
test {
name: "eq_double_NaN"
description: "CEL defines all NaN values to be equal."
expr: "1.0 / 0.0 == 1.0 / 0.0"
value: { bool_value: true }
}
test {
name: "eq_string"
expr: "'' == \"\""
Expand Down Expand Up @@ -121,6 +127,17 @@ section {
expr: "['case'] == ['cAse']"
value: { bool_value: false }
}
test {
name: "not_eq_list_length"
expr: "['one'] == [2, 3]"
disable_check: true
value: { bool_value: false }
}
test {
name: "not_eq_list_false_vs_types"
expr: "[1, 'dos', 3] == [1, 2, 4]"
value: { bool_value: false }
}
test {
name: "eq_map_empty"
expr: "{} == {}"
Expand Down Expand Up @@ -156,6 +173,11 @@ section {
expr: "{'key':'value'} == {'Key':'value'}"
value: { bool_value: false }
}
test {
name: "not_eq_map_false_vs_types"
expr: "{'k1': 1, 'k2': 'dos', 'k3': 3} == {'k1': 1, 'k2': 2, 'k3': 4}"
value: { bool_value: false }
}
test {
name: "eq_mixed_types_error"
description: "A mix of types fails during type checks but can't be captured in the conformance tests yet (See google/cel-go#155). Also, if you disable checks it yields {bool_value: false} where it should also yield an error"
Expand Down