Comparison
A comparison tests two values and produces a bool.
| Operator | Test | Level |
|---|---|---|
< | less than | 11 |
<= | less than or equal | 11 |
> | greater than | 11 |
>= | greater than or equal | 11 |
== | equal | 10 |
!= | not equal | 10 |
let a = 10;
let b = 20;
PrintLine("{} {} {} {}", a == b, a != b, a < b, a >= b);
This prints false true true false. The ordering operators bind more tightly than == and !=, and all of them bind more tightly than && and ||, so offset + length <= capacity && capacity != 0 needs no parentheses.
Operand types
Numbers compare under the same operand rules as arithmetic: one type, a literal that takes the other operand's type, or two integers of one signedness, where the narrower widens. A signed and an unsigned integer have no common type:
error: operator '<' cannot compare left operand 'uint64' with right operand 'int64'
note: the operands differ in signedness, so neither converts to the other's type
help: convert one operand with 'as' to the type the operation should use
A literal must fit the other operand's type, so a test that could never be true is caught: with count: uint64, count == -1 is error: integer literal is out of range for type 'uint64'.
What can be compared
| Type | == != | < <= > >= |
|---|---|---|
| integers, floating-point numbers | yes | yes |
| characters | yes | yes, by code |
bool | yes | yes, false before true |
| enums | yes | yes, by the members' values |
| pointers | yes, and with null | yes, by address |
| structures | yes, field by field, when every field supports == | only through declared operators |
| tuples | yes, element by element | no |
| fixed-size arrays | yes, element by element | no |
| variants | yes, case and payload | no |
| optionals, fallibles and sums | yes, between values of one type | no |
| slices, including string literals | no | no |
A structure, tuple or variant compares structurally only when every part can be compared. A structure gets ordering only from the operators it declares: != is derived from a declared ==, > from <, and <= and >= from < and == together — see Operator interfaces. Without them:
error: operator '<' is not defined for 'Point'
note: a struct is compared through the operators it declares, never by its representation
help: declare '<' on 'Point'
An optional compares with none and with a present value directly: found == none, found == 5. See Optionals.
rux 0.4.0 does not yet compare a fixed-size array with an array literal correctly:
values == [1, 2] is false even when the elements are equal. Bind the literal to a name first.Slices
A slice is a view of elements stored elsewhere. Comparing two views would compare the addresses they hold rather than the elements, so Rux refuses it — and a string literal is a char8[..] slice:
let same = name == "Rux";
error: operator '==' is not defined for slice type 'char8[..]'
note: a slice is a view, so comparing the views would compare addresses rather than elements
Compare the elements one at a time, or use a type that declares ==, such as the Text package's String.
Floating-point comparisons
Floating-point comparisons follow IEEE 754. NaN is unordered: it is not equal to anything, itself included, and every ordering test with it is false:
let n = float64::NaN;
PrintLine("{} {} {}", n == n, n != n, n < 1.0);
This prints false true false. See Floating-point types for testing for NaN and for comparing computed values with a tolerance.
Comparisons do not chain
a < b < c is not a range test. It groups as (a < b) < c, which compares a bool with a number:
let inside = 1 < 2 < 3;
error: operator '<' cannot compare left operand 'bool8' with right operand 'int'
Combine two comparisons with &&: low <= value && value <= high.
See also
- Logical — combining comparisons
- Casts — matching operand types before comparing
- Operator interfaces —
==and<for your own types - Learn: Comparison, Equatable, Comparable