OxigenLang Variables and Assignments

OxigenLang provides several ways to declare and assign variables, giving you explicit control over mutability and type safety.

#Untyped Variables

Variables are declared using the walrus operator :=. Untyped variables have no type constraint — their type can change freely on reassignment:

Oxigen
x := 10
name := "OxigenLang"
is_active := True
pi := 3.14

Reassign untyped variables with :=:

Oxigen
x := 10
x := "hello"
x := [1, 2, 3]

Untyped variables cannot use = for reassignment — = is reserved for typed variables:

Oxigen
x := 10
x = 20

#Typed Variables

You can add type annotations to lock a variable's type. OxigenLang offers three forms of typed declaration, each with different mutability semantics.

#Typed Strict: x <type> = value

Declares a variable with a locked type and an immutable value. The value must already be the correct type — no conversion is performed:

Oxigen
x <int> = 10
y <str> = "hello"
  • Type is locked — cannot hold a different type.
  • Value is immutable — =, :=, ++, and -- are all blocked after declaration.

#Typed Walrus: x <type> := value

Declares a variable with a locked type but a mutable value. Attempts to convert the value to the target type at declaration time:

Oxigen
x <int> := 3.9
y <str> := 42
z <bool> := 0
  • x becomes 3 (float truncated to int).
  • y becomes "42" (int displayed as string).
  • z becomes False (0 is falsy).

The type is locked — subsequent reassignments must match the type. The value is mutable — =, :=, ++/-- all work (with type checking).

#Zero-Init: x <type> or x as <type>

Declares a typed variable initialized to its zero value. The value is mutable. The as keyword is optional — x <type> is the preferred convention:

Oxigen
x <int>
y <str>
z <array>
p <Person>
TypeZero Value
int0
float0.0
str""
char\0
boolFalse
array[]
byte0
uint0
tuple()
map{}
setset()
StructInstance with all fields at their zero values

#Reassignment Rules

#= (strict assign)

Only works on typed mutable variables. The value must already be the correct type — no conversion:

Oxigen
x <int> := 10
x = 20

Blocked on immutable variables:

Oxigen
x <int> = 10
x = 20

Blocked on untyped variables:

Oxigen
y := 10
y = 20

#:= (walrus reassign)

For existing typed variables, := performs a strict type check — no implicit conversion. The type remains locked:

Oxigen
x <int> := 10
x := 20

For untyped variables, := updates freely:

Oxigen
x := 10
x := "hello"

#++ / -- (postfix)

Works on mutable integer variables. Blocked on immutable bindings:

Oxigen
x <int> := 5
x++
x--

y <int> = 5
y++

#Unpacking

Arrays and tuples can be unpacked into multiple variables in a single := declaration:

Oxigen
x, y := [1, 2]
a, b, c := [10, 20, 30]
first, second := (100, 200)

This works with any expression that produces an array or tuple:

Oxigen
introduce strings
key, val := strings.split("name=Alice", "=")

fun get_pair() { [42, "hello"] }
num, msg := get_pair()

The number of names on the left must match the number of elements on the right — a mismatch produces an error:

Oxigen
x, y := [1, 2, 3]   // error: expected 2 values, got 3

#Shadowing

Typed variables can be shadowed in inner scopes. The outer binding is unaffected:

Oxigen
x <int> = 10
each i in [1] {
    x <str> = "hello"
}
x

#In-Place Type Conversion

You can convert a variable's type by re-declaring it with a typed walrus:

Oxigen
user_input := "42"
user_input <int> := user_input
user_input

After re-declaration the new type constraint is locked:

Oxigen
user_input := "42"
user_input <int> := user_input
user_input := "hello"

#Summary Table

DeclarationValue MutableType Locked= allowed++/-- allowed
x := 10yesnonoyes
x <int> = 10noyesnono
x <int> := 10yesyesyesyes
x <int>yesyesyesyes
x as <int>yesyesyesyes

#Introspection

Use is_mut() and is_type_mut() to inspect a variable's mutability at runtime:

Oxigen
a := 10
is_mut(a)
is_type_mut(a)

b <int> := 10
is_mut(b)
is_type_mut(b)

c <int> = 10
is_mut(c)
is_type_mut(c)

See the Type System guide for full details on type annotations, conversions, and mutability semantics. See Built-in Functions for the full list of introspection functions.