Light Dark

What Hot Doesn't Have

Hot intentionally omits certain syntax found in other languages. This isn't a limitation—it's a design choice that keeps the language simple and consistent.

No Infix Operators

Hot has no +, -, *, /, ==, !=, <, >, &&, ||, etc.

Instead ofUse
a + badd(a, b)
a - bsub(a, b)
a * bmul(a, b)
a / bdiv(a, b)
a % bmod(a, b)
a == beq(a, b)
a != bne(a, b)
a < blt(a, b)
a > bgt(a, b)
a <= blte(a, b)
a >= bgte(a, b)
a && band(a, b)
a || bor(a, b)
!anot(a)

Why? Consistency. Everything is a function call, with predictable evaluation order and no operator precedence to remember.

No Assignment Operator

Hot has no = for assignment.

Instead ofUse
name = "Alice"name "Alice"
count = 42count 42

Variables are declared by placing the name before the value.

No If/Else Blocks

Hot has no if/else statement syntax.

Instead ofUse
if (x) { a } else { b }if(x, a, b)
if (x) { a }if(x, a)

Or use cond for multiple conditions:

cond {
  lt(x, 0) => "negative"
  eq(x, 0) => "zero"
  => "positive"
}

No Loops

Hot has no for, while, do-while, or any loop constructs.

Instead ofUse
for (x of items)map(items, (x) { ... })
items.filter(...)filter(items, (x) { ... })
items.reduce(...)reduce(items, (acc, x) { ... }, init)
items.forEach(...)for-each(items, (x) { ... })
while (cond) { }Tail-recursive function

Why? Loops imply mutation. Functional transformations are clearer and parallelize better.

Tail Call Optimization (TCO)

Hot has automatic TCO for tail-recursive functions. Use the accumulator pattern for custom iteration:

// Tail-recursive - stack-safe for any list size
sum-list fn cond (xs: Vec, acc: Int): Int {
  is-empty(xs) => { acc }
  => { sum-list(rest(xs), add(acc, first(xs))) }
}

sum-list([1, 2, 3, 4, 5], 0)  // 15

This works for arbitrarily large collections without stack overflow.

No Classes or Interfaces

Hot has no class, interface, extends, or implements.

Instead ofUse
class User { }User type { name: Str }
new User()User({name: "Alice"})
interface PrintableType coercion: Type -> Str
extends BaseClassComposition

Types in Hot are data definitions, not behavior containers. Add behavior with functions:

User type { name: Str, email: Str }

// Functions that work on User
greet-user fn (user: User): Str {
  `Hello, ${user.name}!`
}

// Type coercion for "interface-like" behavior
User -> Str fn (user: User): Str {
  `${user.name} <${user.email}>`
}

No Exceptions

Hot has no throw, try, catch, or finally.

Instead ofUse
throw new Error("msg")err("msg") or Result.Err("msg")
try { } catch { }if(is-ok(result), ..., ...) or match

Use Result types for error handling:

safe-divide fn (a: Int, b: Int): Int {
  if(eq(b, 0),
    err("Division by zero"),
    div(a, b))
}

result safe-divide(10, 0)

// Use match for pattern matching on Result
match result {
  Result.Ok => log(`Result: ${result}`)
  Result.Err => log(`Error: ${result}`)
}

No Mutable Variables

Hot has no let, var, or reassignment.

count 1
count 2  // Creates a NEW binding, shadows the first

This isn't mutation—it's creating a new variable that shadows the old one. For accumulating values, use reduce:

// Instead of: let sum = 0; for (x of items) { sum += x; }
total reduce(items, (sum, x) { add(sum, x) }, 0)

No Return Statement

The last expression in a function body is the return value:

add fn (a: Int, b: Int): Int {
  add(a, b)  // This is returned
}

No return keyword exists.

No Ternary Operator

Hot has no ? : ternary.

Instead ofUse
x ? a : bif(x, a, b)

Summary: The Hot Way

ConceptOther LanguagesHot
Matha + b * cadd(a, mul(b, c))
Comparisona == b && c > dand(eq(a, b), gt(c, d))
Conditionalsif/else blocksif() function or cond
Loopsfor, whilemap, filter, reduce
Objectsclass + newtype + constructor
Errorsthrow/catchResult.Err()/match
Mutationx = x + 1new-x add(x, 1)

The tradeoff: Hot code looks different from JavaScript/Python/etc. The benefit: Complete consistency, easier parallelization, and no hidden complexity.