Comparison and Logic
The six comparison operators always return bool. For primitive types, ==
compares by value; for arrays and structs, comparison is structural
(deep). Strings use lexicographic order. Zolo does not support
Python-style chaining like a < b < c — combine with && when you need a
range check.
Equality, order, floats (IEEE-754), strings and arrays — all return bool.
// Feature: Comparison operators
// Syntax: `==`, `!=`, `<`, `<=`, `>`, `>=`
// When to use: comparing values. Always return `bool`. In Zolo,
// `==` compares by value for primitive types and structurally for
// structs/arrays (deep equality).
// Equality and inequality.
print(1 == 1) // true
print(1 == 2) // false
print(1 != 2) // true
print("alice" == "alice") // true
print("alice" != "bob") // true
// Order.
print(3 > 2) // true
print(3 >= 3) // true
print(1 < 5) // true
print(1 <= 1) // true
// Floats.
print(1.5 < 1.6) // true
print(0.1 + 0.2 == 0.3) // false (IEEE-754!)
// Strings — lexicographic comparison.
print("apple" < "banana") // true
print("Z" < "a") // true (ASCII: Z=90, a=97)
// Arrays — structural comparison.
print([1, 2, 3] == [1, 2, 3]) // true
print([1, 2, 3] == [1, 2, 4]) // false
// Chaining via `&&` (Zolo does NOT support `a < b < c` like Python).
let n = 5
print(0 < n && n < 10) // true
The logical operators &&, || and ! combine boolean values. && and
|| use short-circuit evaluation: the right-hand side is only evaluated
when the left-hand side does not resolve on its own. Precedence is
! > && > ||.
Short-circuit demonstrated with a side-effect function, and precedence between !, && and ||.
// Feature: Logical operators
// Syntax: `&&` (and), `||` (or), `!` (not)
// When to use: combine booleans in conditionals. `&&` and `||`
// short-circuit (the 2nd expression is NOT evaluated if the 1st
// already decides). `!` flips a bool.
// AND — true only if both are true.
print(true && true) // true
print(true && false) // false
print(false && true) // false
// OR — true if at least one is true.
print(true || false) // true
print(false || false) // false
// NOT — flips.
print(!true) // false
print(!false) // true
print(!(1 == 2)) // true
// Short-circuit: `||` stops on the first true.
fn side_effect(name: str) -> bool {
print("evaluated: {name}")
return true
}
let _r = true || side_effect("right") // "right" is NEVER evaluated
print("---")
// `&&` stops on the first false.
let _r2 = false && side_effect("right") // "right" is NOT evaluated
print("---")
// Precedence: `!` > `&&` > `||`.
print(true || false && false) // true (= true || (false && false))
print(!true || true) // true (= (!true) || true)
// Combining with comparisons.
let age = 25
let has_id = true
print(age >= 18 && has_id) // true
print(age < 13 || age > 65) // false
Challenge
In the logical example, change let _r = true || side_effect("right") to
let _r = false || side_effect("right") and observe when the side effect
gets evaluated.
See also