Operators Reference

Every operator in Adama -- precedence, associativity, type compatibility, and examples. Most of this will feel familiar if you've used C, Java, or JavaScript. The interesting wrinkles are division returning maybe<T> (because division by zero is a thing) and the =? pattern match operator.

Operator Precedence

Operators listed from highest to lowest precedence. Higher precedence binds more tightly.

Precedence Operators Description Associativity
1 () [] . Grouping, indexing, member access Left to right
2 ! - ++ -- Unary operators Right to left
3 * / % Multiplicative Left to right
4 + - Additive Left to right
5 < <= > >= =? Relational Left to right
6 == != Equality Left to right
7 && Logical AND Left to right
8 || Logical OR Left to right
9 ?: Ternary conditional Right to left
10 = += -= *= Assignment Right to left

Arithmetic Operators

Addition (+)

Adds two values or concatenates strings.

Left Type Right Type Result Type Description
int int int Integer addition
int long long Promoted to long
int double double Promoted to double
long long long Long addition
long double double Promoted to double
double double double Floating point addition
string any string String concatenation
any string string String concatenation
complex complex complex Complex addition
vec2 vec2 vec2 Vector addition
vec3 vec3 vec3 Vector addition
vec4 vec4 vec4 Vector addition
timespan timespan timespan Duration addition

Examples:

int a = 5 + 3;              // 8
double b = 5 + 3.14;        // 8.14
string c = "Hello, " + "World!";  // "Hello, World!"
string d = "Count: " + 42;  // "Count: 42"
vec3 v = @vec[1,0,0] + @vec[0,1,0];  // @vec[1,1,0]

Subtraction (-)

Subtracts the right operand from the left operand.

Left Type Right Type Result Type Description
int int int Integer subtraction
int long long Promoted to long
int double double Promoted to double
long long long Long subtraction
long double double Promoted to double
double double double Floating point subtraction
complex complex complex Complex subtraction
vec2 vec2 vec2 Vector subtraction
vec3 vec3 vec3 Vector subtraction
vec4 vec4 vec4 Vector subtraction
timespan timespan timespan Duration subtraction

Examples:

int a = 10 - 3;             // 7
double b = 10.5 - 3.2;      // 7.3
vec3 v = @vec[5,5,5] - @vec[1,2,3];  // @vec[4,3,2]

Multiplication (*)

Multiplies two values.

Left Type Right Type Result Type Description
int int int Integer multiplication
int long long Promoted to long
int double double Promoted to double
long long long Long multiplication
long double double Promoted to double
double double double Floating point multiplication
string int string String repetition
complex complex complex Complex multiplication
vec2 vec2 double Dot product
vec3 vec3 double Dot product
vec4 vec4 double Dot product
vec2 double vec2 Scalar multiplication
vec3 double vec3 Scalar multiplication
vec4 double vec4 Scalar multiplication
double vec2 vec2 Scalar multiplication
double vec3 vec3 Scalar multiplication
double vec4 vec4 Scalar multiplication
mat4 mat4 mat4 Matrix multiplication
mat4 vec4 vec4 Matrix-vector multiplication
math4 vec3 vec3 Homogeneous transformation
timespan double timespan Duration scaling
double timespan timespan Duration scaling

Examples:

int a = 5 * 3;              // 15
double b = 5.0 * 2.5;       // 12.5
string c = "ha" * 3;        // "hahaha"
double dot = @vec[1,0,0] * @vec[0,1,0];  // 0.0 (perpendicular)
vec3 scaled = @vec[1,2,3] * 2.0;  // @vec[2,4,6]

Division (/)

Divides the left operand by the right operand.

Important: Division always returns maybe<T> because division by zero is possible. I know it's a bit annoying to unwrap every time, but it beats a runtime crash.

Left Type Right Type Result Type Description
int int maybe<double> Integer division
int long maybe<double> Promoted division
int double maybe<double> Promoted division
long long maybe<double> Long division
long double maybe<double> Promoted division
double double maybe<double> Floating point division
complex complex maybe<complex> Complex division

Examples:

maybe<double> a = 10 / 3;   // Contains ~3.333
maybe<double> b = 10 / 0;   // Empty (division by zero)

// Safe usage with getOrDefaultTo
double result = (10 / 2).getOrDefaultTo(-1);  // 5.0
double safe = (10 / 0).getOrDefaultTo(-1);    // -1.0

int x = 10;
int y = 3;

@construct {
  // Pattern matching
  if ((x / y) as quotient) {
    // quotient is a double
  }
}

Modulo (%)

Returns the remainder after division.

Important: Modulo returns maybe<T> because modulo by zero is undefined. Same logic as division.

Left Type Right Type Result Type Description
int int maybe<int> Integer modulo
long long maybe<long> Long modulo
vec2 vec2 double 2D cross product (scalar)
vec3 vec3 vec3 3D cross product (vector)

Examples:

maybe<int> a = 10 % 3;      // Contains 1
maybe<int> b = 10 % 0;      // Empty (modulo by zero)

int remainder = (17 % 5).getOrDefaultTo(0);  // 2

// Cross product
vec3 cross = @vec[1,0,0] % @vec[0,1,0];  // @vec[0,0,1]

Unary Minus (-)

Negates a numeric value.

Operand Type Result Type Description
int int Integer negation
long long Long negation
double double Floating point negation
complex complex Complex negation
vec2 vec2 Vector negation
vec3 vec3 Vector negation
vec4 vec4 Vector negation

Examples:

int a = -5;                 // -5
double b = -3.14;           // -3.14
vec3 v = -@vec[1,2,3];      // @vec[-1,-2,-3]

Comparison Operators

Equality (==)

Returns true if operands are equal.

Left Type Right Type Result Type
int int bool
long long bool
double double bool
bool bool bool
string string bool
principal principal bool
label label bool
date date bool
time time bool
datetime datetime bool
asset asset bool
enum same enum bool

Examples:

enum Status { Active, Inactive }
private principal owner;
private Status status;

bool a = (5 == 5);          // true
bool b = ("hi" == "hi");    // true

@connected {
  bool c = (@who == owner);   // depends on context
  bool d = (status == Status::Active);  // enum comparison
  return true;
}

Inequality (!=)

Returns true if operands are not equal.

Same type combinations as ==.

Examples:

bool a = (5 != 3);          // true
bool b = ("hi" != "bye");   // true

@connected {
  bool c = (@who != @no_one); // true if authenticated
  return true;
}

Less Than (<)

Returns true if left operand is less than right operand.

Left Type Right Type Result Type
int int bool
long long bool
double double bool
string string bool
date date bool
time time bool
datetime datetime bool

Examples:

bool a = (3 < 5);           // true
bool b = (3.14 < 2.71);     // false
bool c = ("apple" < "banana");  // true (lexicographic)

Less Than or Equal (<=)

Returns true if left operand is less than or equal to right operand.

Same type combinations as <.

Examples:

bool a = (3 <= 5);          // true
bool b = (5 <= 5);          // true

Greater Than (>)

Returns true if left operand is greater than right operand.

Same type combinations as <.

Examples:

bool a = (5 > 3);           // true
bool b = (3.14 > 2.71);     // true

Greater Than or Equal (>=)

Returns true if left operand is greater than or equal to right operand.

Same type combinations as <.

Examples:

bool a = (5 >= 3);          // true
bool b = (5 >= 5);          // true

Pattern Match (=?)

Returns true if the left string matches the right pattern. Glob-style matching.

Left Type Right Type Result Type Description
string string bool Glob-style pattern matching

Pattern Syntax:

  • * matches zero or more characters
  • ? matches exactly one character

Examples:

bool a = "hello" =? "hel*";     // true
bool b = "hello" =? "h*o";      // true
bool c = "hello" =? "h?llo";    // true
bool d = "hello" =? "world";    // false
bool e = "test.txt" =? "*.txt"; // true

Logical Operators

Logical AND (&&)

Returns true if both operands are true. Short-circuits: if the left operand is false, the right side never runs.

Left Type Right Type Result Type
bool bool bool

Examples:

private principal user;
private principal owner;

bool a = true && true;      // true
bool b = true && false;     // false
bool c = false && true;     // false (short-circuits)

@connected {
  // Common pattern: guard checks
  if (user != @no_one && user == owner) {
    // Safe: second condition only evaluated if user is not @no_one
  }
  return true;
}

Logical OR (||)

Returns true if either operand is true. Short-circuits: if the left operand is true, the right side never runs.

Left Type Right Type Result Type
bool bool bool

Examples:

bool isOwner = false;
bool isAdmin = false;
bool isPublic = true;

bool a = true || false;     // true (short-circuits)
bool b = false || true;     // true
bool c = false || false;    // false

// Common pattern: default values
bool allowed = isOwner || isAdmin || isPublic;

Logical NOT (!)

Returns the logical inverse of the operand.

Operand Type Result Type
bool bool

Examples:

bool isBlocked = false;
bool isExpired = false;

bool a = !true;             // false
bool b = !false;            // true
bool c = !(5 > 3);          // false

@construct {
  // Common pattern: negation checks
  if (!isBlocked && !isExpired) {
    // Process request
  }
}

Assignment Operators

Simple Assignment (=)

Assigns the right operand to the left operand.

Examples:

int x = 5;
string name = "Alice";
bool active = true;

Addition Assignment (+=)

Adds the right operand to the left operand and assigns the result.

Examples:

int x = 10;
string s = "Hello";

@construct {
  x += 5;                     // x is now 15
  s += " World";              // s is now "Hello World"
}

Subtraction Assignment (-=)

Subtracts the right operand from the left operand and assigns the result.

Examples:

int x = 10;

@construct {
  x -= 3;                     // x is now 7
}

Multiplication Assignment (*=)

Multiplies the left operand by the right operand and assigns the result.

Examples:

int x = 5;
double d = 2.5;

@construct {
  x *= 3;                     // x is now 15
  d *= 2;                     // d is now 5.0
}

Increment and Decrement Operators

Prefix Increment (++x)

Increments the operand and returns the new value.

Examples:

int x = 5;
int y = ++x;                // x is 6, y is 6

Postfix Increment (x++)

Returns the current value, then increments the operand.

Examples:

int x = 5;
int y = x++;                // y is 5, x is 6

Prefix Decrement (--x)

Decrements the operand and returns the new value.

Examples:

int x = 5;
int y = --x;                // x is 4, y is 4

Postfix Decrement (x--)

Returns the current value, then decrements the operand.

Examples:

int x = 5;
int y = x--;                // y is 5, x is 4

Ternary Conditional Operator

Conditional Expression (? :)

Returns one of two values based on a condition.

Syntax: condition ? value_if_true : value_if_false

Examples:

int a = 5;
int b = 3;
bool isActive = true;
private principal player1;
private principal player2;
private principal current;

int max = (a > b) ? a : b;
string status = isActive ? "Active" : "Inactive";
principal next = (current == player1) ? player2 : player1;

Member Access Operators

Dot Operator (.)

Accesses a member of a record, object, or calls a method.

Examples:

record Name {
  public string first;
}
record Profile {
  public Name name;
}
record User {
  public string name;
  public Profile profile;
}
record Position {
  public int x;
}

Position position;
User user;
string text = "hello";
maybe<int> value;

// Field access
public formula fx = position.x;
public formula fn = user.name;

// Method calls
public formula flen = text.length();
public formula fhas = value.has();

// Chained access
public formula first = user.profile.name.first;

Index Operator ([])

Accesses an element by index (arrays/lists) or key (maps).

Examples:

map<string, int> scores;

@construct {
  // Map access
  maybe<int> score = scores["Alice"];
}

Table Operators

Insert Operator (<-)

Inserts a new record into a table.

Examples:

record Player {
  public string name;
  public int score;
}
table<Player> _players;

record Msg {
  public principal sender;
  public string text;
  public datetime timestamp;
}
table<Msg> _messages;

message ChatMsg {
  string text;
}

channel chat(ChatMsg msg) {
  _players <- {name: "Alice", score: 0};
  _messages <- {sender: @who, text: msg.text, timestamp: Time.datetime()};
}

Type Summary

Category Operators
Arithmetic + - * / % (unary -)
Comparison == != < <= > >= =?
Logical && || !
Assignment = += -= *=
Increment/Decrement ++ --
Conditional ?:
Access . []
Table <-

Common Patterns

Safe Division

int numerator = 10;
int denominator = 3;
int a = 10;
int b = 3;

// Always handle the maybe result
double result = (numerator / denominator).getOrDefaultTo(0.0);

@construct {
  // Or use pattern matching
  if ((a / b) as quotient) {
    // Use quotient safely
  }
}

Compound Conditions

bool isActive = true;
bool isBlocked = false;
string role = "admin";

@construct {
  // Check multiple conditions
  if (isActive && !isBlocked && (role == "admin" || role == "owner")) {
    // Allow action
  }
}

Null-Safe Principal Checks

private principal owner;

@connected {
  // Always check for @no_one before comparing principals
  if (@who != @no_one && @who == owner) {
    // User is authenticated and is the owner
  }
  return true;
}

String Building

string userName = "Alice";
int score = 100;

// Concatenate multiple values
string message = "User " + userName + " scored " + score + " points";

// Repeat strings
string separator = "-" * 20;  // "--------------------"
Previous At Constants
Next Errors