Skip to content

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.

02-comparison.zolo
Playground
// 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 ||.

03-logical.zolo
Playground
// 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

enespt-br