Alpha. Vary is under active development and not ready for production use. Syntax, APIs, performance, and behaviour may change between releases.

Basics

Comments

Comments start with # and run to the end of the line. There are no block comments.

# This is a comment
let x = 42  # inline comment

Variables

Use let for immutable bindings and mut for mutable ones. Type annotations are optional when the type can be inferred.

let x = 42
let name: Str = "Alice"
mut counter = 0
counter = counter + 1
counter += 1            # compound assignment (also -=, *=, /=)

Variables declared at module level are accessible from all functions in the module:

let MAX_SIZE = 100

def check_size(n: Int) -> Bool {
    return n <= MAX_SIZE
}

Types

Every value has a type known at compile time. See Types for the full reference.

Primitives

TypeExample
Int42
Float3.14
BoolTrue, False
Str"hello"
Neverreturn type for functions that never return (e.g. exit())

Optional types

Append ? to any type to make it optional. Optional values are either a value of that type or None.

let result: Int? = find("Alice")

if result is not None {
    print(result + 1)       # narrowed to Int inside this block
}
if result is None {
    print("not found")
}

let value = result ?: 0     # elvis: use 0 if None
let upper = name?.upper()   # safe call: returns None if name is None
let forced = result!!       # non-null assertion (throws if None)

is None and is not None are the idiomatic way to check for None. The equality forms == None and != None also work and trigger the same flow narrowing.

Tuples

Fixed-size groups of values with potentially different types:

let point = (1, 2)
let (x, y) = point         # destructuring
let (a, b, c?) = (1, 2)    # optional element: c is None

Tuples support 2 to 8 elements. For larger groupings, use a data type.

Function types

let transform: (Int) -> Int = lambda x: Int: x * 2

Generics

Classes, data types, and functions can take type parameters:

data Pair[A, B] {
    first: A
    second: B
}

def identity[T](x: T) -> T {
    return x
}

Type arguments are inferred from usage. See Types for more.

Strings

Strings use double quotes. F-strings embed expressions with f"...":

let name = "world"
print(f"Hello, {name}!")
print(f"2 + 2 = {2 + 2}")

Indexing and slicing:

let s = "Hello, World!"
print(s[0])         # "H"
print(s[0:5])       # "Hello"
print(s[7:])        # "World!"

Common methods: upper(), lower(), strip(), split(sep), split_once(sep), join(list), replace(old, new), startswith(prefix), endswith(suffix), is_empty(), non_empty(). See Collections and strings for the full list.

Raw strings

Prefix a string with r to disable escape processing. Useful for regex patterns and file paths:

let pattern = r"\d+\.\d+"
let path = r"C:\Users\name\docs"

Both r"..." and r'...' are supported.

Triple-quoted strings

Use """...""" for multiline strings. Triple-quoted strings support escape sequences and automatically strip common leading indentation:

let sql = """
    SELECT name, age
    FROM users
    WHERE active = true
    """
# Result: "SELECT name, age\nFROM users\nWHERE active = true"

Auto-dedent rules: the leading newline after """, the trailing newline before closing """, and the common leading whitespace of all non-empty lines are removed. Escape sequences (\n, \t, \\, etc.) work inside triple-quoted strings.