Comparison
Programs constantly ask questions about their values. Is the user old enough? Is the tank empty? Did the score beat the record? A comparison asks one such question about two values, and the answer is always a bool — true or false. That answer is what the next part, Control flow, uses to decide what runs.
Six questions
| Operator | Asks | 17 and 5 give |
|---|---|---|
== | equal? | false |
!= | not equal? | true |
< | less than? | false |
<= | less than or equal? | false |
> | greater than? | true |
>= | greater than or equal? | true |
Equality is written with two equals signs. A single = is assignment, which changes a variable rather than asking about it.
let a: int32 = 17;
let b: int32 = 5;
PrintLine("{} == {} is {}", a, b, a == b);
PrintLine("{} != {} is {}", a, b, a != b);
A comparison is a value
The answer is an ordinary bool, so it can be printed, passed along, or kept in a variable with a name that says what it means:
let age: int32 = 18;
let adult = age >= 18;
PrintLine("age {} is adult: {}", age, adult);
adult is a bool, inferred from the comparison. Naming a condition this way often makes the code that later tests it read like a sentence.
Both sides must agree
Like arithmetic, a comparison needs operands of compatible types. Two integers of the same signedness may differ in width — an int8 compares with an int64, because the narrower one widens without loss. Everything else is refused:
| Left | Right | Result |
|---|---|---|
int32 | int32 | compared |
int8 | int64 | compared — the int8 widens |
int32 | uint32 | refused — the operands differ in signedness |
int32 | float64 | refused — convert one side with as first |
Characters compare by code point
A character is a number underneath, as Convert showed, and comparing characters compares those numbers. Every capital letter comes before every lowercase one, so 'Z' sorts ahead of 'a':
let upper: char32 = 'Z';
let lower: char32 = 'a';
PrintLine("'{}' < '{}' is {}", upper, lower, upper < lower);
That is alphabetical order only within one case — worth remembering before sorting names.
Floats and exact equality
Float showed that 0.1 + 0.2 is not exactly 0.3. == sees the difference, however tiny:
let sum: float64 = 0.1 + 0.2;
PrintLine("0.1 + 0.2 == 0.3 is {}", sum == 0.3);
PrintLine("0.1 + 0.2 > 0.3 is {}", sum > 0.3);
The sum lands just above 0.3, so == says false and > says true. Ordering comparisons on floats are fine; be wary of exact == between floats that came out of arithmetic. Ask instead whether two values are close enough — whether their difference is below some small tolerance you choose.
Comparisons do not chain
In maths, 1 < age < 30 means "age is between 1 and 30". In Rux, it does not:
flowchart LR
expr["1 < age < 30"] --> first["1 < age<br/>is worked out first"]
first --> b["a bool:<br/>true or false"]
b --> second["that bool < 30"]
second --> err["error: operator '<' cannot compare<br/>left operand 'bool8'<br/>with right operand 'int'"]The first comparison produces a bool, and a bool cannot be compared with a number. Asking two questions at once takes && — 1 < age && age < 30 — the subject of the next lesson.
The program
The whole lesson is one package in the Examples repository. Its comments explain every step.
// The six comparison operators ask a yes-or-no question about two values:
// `==` equal, `!=` not equal, `<` less, `<=` less or equal, `>` greater and
// `>=` greater or equal. Whatever the operands are, the answer is a `bool`, so
// it can be printed or kept in a variable like any other value.
import Io::PrintLine;
func Main() -> int {
let a: int32 = 17;
let b: int32 = 5;
PrintLine("{} == {} is {}", a, b, a == b);
PrintLine("{} != {} is {}", a, b, a != b);
PrintLine("{} < {} is {}", a, b, a < b);
PrintLine("{} <= {} is {}", a, b, a <= b);
PrintLine("{} > {} is {}", a, b, a > b);
PrintLine("{} >= {} is {}", a, b, a >= b);
// A comparison is an ordinary expression, and its result is a value.
let age: int32 = 18;
let adult = age >= 18;
PrintLine("age {} is adult: {}", age, adult);
// Characters compare by code point. Every capital letter comes before every
// lowercase one, so 'Z' sorts ahead of 'a'.
let upper: char32 = 'Z';
let lower: char32 = 'a';
PrintLine("'{}' < '{}' is {}", upper, lower, upper < lower);
// Floats are stored approximately, so a sum that looks exact on paper can
// miss by a hair, and `==` sees the hair: this sum lands just above 0.3. Be
// wary of exact `==` between floats that came out of arithmetic.
let sum: float64 = 0.1 + 0.2;
PrintLine("0.1 + 0.2 == 0.3 is {}", sum == 0.3);
PrintLine("0.1 + 0.2 > 0.3 is {}", sum > 0.3);
// Comparisons do not chain the way they do in maths. `1 < age < 30` would
// compare `1 < age`, a `bool`, against 30, and the compiler rejects that.
// Asking two questions at once needs `&&`, the subject of the next lesson.
return 0;
}
Run it
cd Examples/Operators/Comparison
rux run
17 == 5 is false
17 != 5 is true
17 < 5 is false
17 <= 5 is false
17 > 5 is true
17 >= 5 is true
age 18 is adult: true
'Z' < 'a' is true
0.1 + 0.2 == 0.3 is false
0.1 + 0.2 > 0.3 is true
Common mistakes
1 < age < 30 fails with error: operator '<' cannot compare left operand 'bool8' with right operand 'int': the left half is already a bool. Write 1 < age && age < 30.When
age is an int32 and limit is a float64, age > limit fails with error: operator '>' cannot compare left operand 'int32' with right operand 'float64'. Convert one side with as.An
int32 and a uint32 are refused too — note: the operands differ in signedness, so neither converts to the other's type — and the compiler's help suggests converting one operand with as.0.1 + 0.2 == 0.3 is false. Compare the difference against a small tolerance instead.Try it yourself
- Compare
'a'with'b', and'9'with'A'. Print the code points withas uint32to see why. - Declare
let temperature: int32 = 21;and aboolnamedcomfortablethat istruefrom 18 to 24. You will need&&from the next lesson. - Print
0.1 + 0.2 - 0.3to see how far the sum misses. - Write
1 < age < 30and read the error, then fix it.
Learn more
- Comparison operations in the Rux Reference
- Logical — combining several comparisons into one condition
- Equatable and Comparable — making your own types comparable