Skip to content
La3 Docs
Browse docs

Operators and Expressions

Precedence, arithmetic semantics, optional operators, casts, assignment, and expression values.

Expression model

Most constructs that compute a value can appear wherever a value is expected.

La3 uses expressions to keep examples direct. A block can return its final expression, if can choose a value, match can compute a result, and loop can finish with break value. The reader sees data flow instead of a trail of mutable temporaries.

  • Statements are still available where a value is not needed.
  • An early return is allowed and should be used for guard clauses.
  • Branches that produce values must agree on type.
  • The type checker treats expression value and control-flow reachability as one semantic unit.

Arithmetic semantics

Numeric operators have explicit, documented behaviour so examples do not depend on host-language guesses.

  • Integer / truncates toward zero.
  • % keeps the sign of the left operand.
  • // is floor division.
  • ** always produces f64 because exponentiation naturally escapes integer-only results.
  • Mixed numeric arithmetic requires an explicit as cast.
let a = 7 / 2        // 3
let b = -7 / 2       // -3
let c = -7 // 2      // -4
let d = 2 ** 10      // f64

Logical operators

&&, ||, and ! are boolean operators, not value-selection operators.

La3 deliberately avoids the Lua convention where logical operators return one of their operands. That idiom is compact, but in a language that otherwise resembles Rust, C, and TypeScript it would make familiar syntax mean something surprising.

  • && evaluates the right side only when the left side is true.
  • || evaluates the right side only when the left side is false.
  • Both operators always produce bool.
  • Use ?? for value defaults and ?. for optional access.

Optional operators

?? and ?. are the lightweight control-flow operators for T | nil.

  • left ?? right evaluates right only when left is nil.
  • receiver?.field returns nil when receiver is absent.
  • Chained optional access short-circuits at the first absent link.
  • Option<T> has its own method vocabulary, including map, unwrap_or, and ?.
let port = opts.port ?? 443
let city = user?.address?.city ?? "unknown"

Casts

as marks every conversion that can change representation or lose information.

The checker accepts numeric-to-numeric casts and integer-to-char or char-to-integer casts. It rejects conversions that would pretend unrelated runtime representations are the same thing, such as a string cast directly to an integer.

  • Float-to-integer casts truncate.
  • Integer narrowing keeps the low bits of the value.
  • There is no implicit widening just because the destination type is larger.
  • The docs should show casts at protocol boundaries, binary formats, and size conversions.