Skip to content

Operators

This page provides a complete reference for all operators in Tova, organized by category and including a full precedence table.

Arithmetic Operators

OperatorNameExampleResult
+Addition3 + 47
-Subtraction10 - 37
*Multiplication4 * 520
/Division10 / 33.333...
%Modulo10 % 31
**Power2 ** 101024

For string concatenation, use + or string interpolation:

tova
"hello" + " " + "world"   // "hello world"
"{first} {last}"           // string interpolation (preferred)

The * operator supports string repetition when used with a string and a number:

tova
"-" * 40    // "----------------------------------------"
"abc" * 3   // "abcabcabc"

Unary - negates a number:

tova
x = 42
y = -x     // -42

Comparison Operators

OperatorNameExample
==Equalx == 10
!=Not equalx != 10
<Less thanx < 10
<=Less than or equalx <= 10
>Greater thanx > 10
>=Greater than or equalx >= 10

Chained Comparisons

Tova supports chained comparisons, which read naturally as mathematical inequalities:

tova
1 < x < 10          // true when x is between 1 and 10 (exclusive)
0 <= score <= 100    // true when score is in [0, 100]
a < b < c < d        // true when a < b AND b < c AND c < d

Each intermediate value is evaluated only once. Chained comparisons desugar to a conjunction of pairwise comparisons.

Logical Operators

Tova provides both keyword and symbolic forms. The keyword forms are idiomatic:

KeywordSymbolMeaningExample
and&&Logical ANDx > 0 and x < 10
or||Logical ORx == 0 or x == 1
not!Logical NOTnot is_empty

Both forms are fully interchangeable:

tova
// Keyword style (preferred)
if is_valid and not is_expired {
  process(item)
}

// Symbol style (also valid)
if is_valid && !is_expired {
  process(item)
}

Logical operators use short-circuit evaluation: and does not evaluate the right operand if the left is falsy, and or does not evaluate the right if the left is truthy.

Membership Operators

OperatorMeaningExample
inContained in"a" in list
not inNot contained inx not in banned
tova
if item in allowed_items {
  accept(item)
}

if user not in banned_users {
  grant_access(user)
}

Type Checking Operators

OperatorMeaningExample
isType check (true if value is of type)x is String
is notNegated type checkx is not Nil

The is operator tests the runtime type of a value. It works with built-in types and ADT variants:

tova
value = "hello"
value is String       // true
value is Int          // false
value is not Nil      // true
tova
// With ADT variants
result = Ok(42)
if result is Ok {
  print("Success!")
}

option = Some("data")
if option is not None {
  print("Has value")
}

Supported type checks: String, Int, Float, Bool, Nil, Array, Function, Number, and any custom ADT variant name.

Assignment Operators

OperatorMeaningEquivalent
=Assignx = 10
+=Add and assignx = x + 10
-=Subtract and assignx = x - 10
*=Multiply and assignx = x * 10
/=Divide and assignx = x / 10
tova
var counter = 0
counter += 1       // counter is now 1
counter *= 5       // counter is now 5

Pipe Operator

The pipe operator |> passes the result of the left expression as the first argument to the function on the right:

tova
// Without pipes
result = format(filter(map(data, transform), predicate))

// With pipes -- reads left to right
result = data
  |> map(transform)
  |> filter(predicate)
  |> format()

Placeholder _

Use _ as a placeholder to control where the piped value is inserted:

tova
10 |> add(_, 5)         // add(10, 5)
"hello" |> replace(_, "l", "r")  // replace("hello", "l", "r")

Method Pipe

Use .method() syntax to call a method on the piped value:

tova
items
  |> .filter(fn(x) x > 0)
  |> .map(fn(x) x * 2)
  |> .join(", ")

Range Operators

OperatorNameExampleMeaning
..Exclusive range0..50, 1, 2, 3, 4
..=Inclusive range0..=50, 1, 2, 3, 4, 5
tova
for i in 0..10 {       // 0 through 9
  print(i)
}

for i in 1..=100 {     // 1 through 100 (inclusive)
  print(i)
}

Spread Operator

The ... spread operator expands an iterable into individual elements:

tova
a = [1, 2, 3]
b = [...a, 4, 5]       // [1, 2, 3, 4, 5]

opts = {color: "red"}
full = {...opts, size: 10}  // {color: "red", size: 10}

It also works in function calls:

tova
args = [1, 2, 3]
sum(...args)            // sum(1, 2, 3)

Optional Chaining

The ?. operator accesses a property only if the receiver is not nil:

tova
user?.address?.city     // nil if user or address is nil
items?.length           // nil if items is nil

Nil Coalescing

The ?? operator returns the left operand if it is not nil, otherwise the right:

tova
name = user?.name ?? "Anonymous"
port = config?.port ?? 3000

Member Access and Subscript

OperatorNameExample
.Member accessuser.name
[]Subscript / indexitems[0]
tova
point.x                 // access field x
matrix[0][1]            // nested indexing
map["key"]              // string subscript

Fat Arrow and Thin Arrow

OperatorNameUsage
=>Fat arrowMatch arms, route handlers, short lambdas
->Return typeFunction return type annotations
tova
// Fat arrow in match
match status {
  200 => "OK"
  404 => "Not Found"
  _ => "Unknown"
}

// Thin arrow for return types
fn add(a: Int, b: Int) -> Int {
  a + b
}

Other Operators

OperatorNameUsage
:Type annotation / object fieldx: Int, {name: "Alice"}
::Slice stepitems[::2], items[1::3]
++String prefix matching (in match patterns)"api/" ++ rest

Operator Precedence

Operators are listed from highest precedence (binds tightest) to lowest (binds loosest). Operators on the same row have equal precedence.

LevelOperatorsAssociativityDescription
13. ?. [] ()LeftMember access, optional chain, subscript, call
12- (unary) ... (spread)RightUnary negation, spread
11**RightExponentiation
10* / %LeftMultiplication, division, modulo
9+ -LeftAddition, subtraction
8.. ..=NoneRange (exclusive, inclusive)
7in not inLeftMembership test
6< <= > >= == != is is notLeftComparison, type checking (chainable)
5not !RightLogical NOT
4and &&LeftLogical AND
3or ||LeftLogical OR
2??LeftNull coalescing
1|>LeftPipe

Precedence Examples

tova
// ** binds tighter than unary -
-2 ** 3          // -(2 ** 3) = -8

// * binds tighter than +
2 + 3 * 4        // 2 + (3 * 4) = 14

// and binds tighter than or
a or b and c     // a or (b and c)

// |> has lowest precedence
data |> f() |> g()  // g(f(data))

// ?? binds tighter than |> but looser than or
a ?? b |> f()    // f(a ?? b)

Released under the MIT License.