Variables & Types
Toka is a statically-typed language with a rich type system. Let's explore how variables and types work.
Variable Declaration
Use the auto keyword to declare variables:
auto x = 10 // i32 (default integer type)
auto y = 3.14 // f64 (default float type)
auto name = "Toka" // str (string slice)
Naming Rules & Hyphen (-) Resolution
Toka has a strict and elegant rule regarding the hyphen (-) character to achieve both modular naming convenience and unambiguous mathematical syntax:
Package Names & Namespaces
Filesystem path segments in an import may use hyphens. Names that enter Toka's semantic namespace—including an import alias and the namespace used at a call site—must be ordinary identifiers, so use an underscore alias for a kebab-case path:
import std/io::println
// The path may contain hyphens; the alias may not.
import ./nested/toka-ink as toka_ink
fn main() -> i32 {
toka_ink::render()
return 0
}
Variables & Functions
Ordinary variable names, constant names, shape/struct names, and function definitions cannot contain hyphens. They must follow standard alphanumeric/underscore naming rules (such as camelCase or snake_case):
fn main() {
auto max_size = 1024 // OK (snake_case)
auto maxSize = 1024 // OK (camelCase)
// auto max-size = 1024 // Error: Hyphens are not allowed in variable names
}
Unambiguous Subtraction
Because hyphens are strictly forbidden in variable and function names, the subtraction operator (-) is unambiguous. For readability and to keep the lexer boundary explicit, binary subtraction must be surrounded by spaces:
import std/io::println
fn main() -> i32 {
auto sub1 = 10
auto sub2 = 3
auto result = sub1 - sub2
auto value = 10 - 3
println("Result: {}, Value: {}", result, value)
return 0
}
Explicit Type Annotations
auto always infers the binding type and cannot carry a declaration-side type annotation. To constrain inference, ascribe the initializer with : Type:
auto x = 10:u64
auto y = 3.14:f32
auto flag = true:bool
Absence Is Not One Type
Toka 1.0 keeps three absence domains distinct: a nullable handle uses nul *T, nul ^T, or nul ~T and the value null; a nullable payload uses T? and none; and an optional operation result uses Option<T>::None. These forms do not implicitly convert into one another. Use guard or ?? for the selected nullable layer, and use postfix ! only to propagate Option or Result.
Primitive Types
Toka's type system is defined in lib/core/types.tk and includes:
| Type | Description | Size |
|---|---|---|
i8, i16, i32, i64 | Signed integers | 1-8 bytes |
u8, u16, u32, u64 | Unsigned integers | 1-8 bytes |
f32, f64 | Floating point (IEEE 754) | 4-8 bytes |
bool | Boolean (true / false) | 1 byte |
char | C-style character (i8) | 1 byte |
byte | Raw byte (u8) | 1 byte |
Platform-Dependent Types
pub alias usize = u64 // Pointer-sized unsigned integer
pub alias isize = i64 // Pointer-sized signed integer
On 64-bit systems, usize is u64; on 32-bit systems, it would be u32.
Type Aliases
Toka supports two kinds of type aliases:
Weak alias — Semantically identical, transparent to the compiler:
pub alias usize = u64
Strong type — Same memory layout, but requires explicit conversion:
pub type Addr = u64
pub type OAddr = u64
Constants
Use const for compile-time constant values:
pub const MAX_SIZE = 1024:u64
pub const NAME = "Toka"
Constants are inlined at compile time — no memory is allocated and their address cannot be taken.
Mutability
Variables are immutable by default. Use the # suffix to make them mutable. The # token is only needed in two places:
- At declaration — to mark the variable as mutable
- Before a mutable method call — to present the guard on the variable
import std/io::println
pub shape List(data: i32)
impl List {
pub fn sort(self#) {}
pub fn push(self#, val: i32) {}
}
fn main() -> i32 {
auto y = List(data = 10) // immutable
auto x# = List(data = 10) // mutable — # at declaration
// Reading and assignment don't need #
x = List(data = 20) // OK — plain assignment
println("{}", x.data) // OK — plain read
// Calling a mutable method requires # on the variable
x#.sort() // OK — # on variable before .method()
x#.push(5) // OK
return 0
}
This is an example of Toka's Attribute Token System — the # suffix denotes soul mutability and is placed on the variable itself when declaring it or calling its mutable methods.