Variables and Types in Odin
Learn about variables, data types, distinct types, and type conversions in Odin with practical Docker-ready examples
Odin is statically and strongly typed — every variable has a fixed type determined at compile time. Odin’s declaration syntax reads left-to-right: name : type = value for variables, name :: value for constants. This contrasts with C’s right-to-left type name ordering and makes declarations read naturally as “name is a type, initialized to value.”
What sets Odin apart from most systems languages is its distinct type system. You can create new types that share the same underlying representation as an existing type but are completely incompatible at compile time. This catches unit-mismatch bugs — like accidentally dividing meters by kilograms — before your code ever runs. Combined with Odin’s strict rule against implicit type conversions, the compiler becomes a powerful ally for correctness.
In this tutorial you will learn how to declare variables and constants, work with Odin’s primitive types, convert between types explicitly, and use distinct types and enumerations to make your code safer.
Variable Declarations
Odin offers two declaration styles. Explicit declarations spell out the type: name : type = value. Short declarations use := to let the compiler infer the type from the value. Constants use :: and are evaluated at compile time. Every variable in Odin has a zero value — the type-specific default when no initializer is provided.
Create a file named variables.odin:
| |
The declaration patterns break down like this: a single : introduces the type, and = assigns a value. Two colons :: means the binding is constant. So x : int = 5 is a mutable variable, x := 5 is a mutable variable with inferred type, X :: 5 is a constant with inferred type, and X : int : 5 is a constant with an explicit type.
Zero values guarantee that variables are always initialized. Numeric types default to 0, booleans to false, and strings to the empty string. This eliminates the undefined-variable bugs common in C.
Types, Conversions, and Distinct Types
Odin provides sized integer types with guaranteed widths (i8, i16, i32, i64 and their unsigned counterparts u8, u16, u32, u64), two float types (f32, f64), and built-in string, bool, and rune types. The plain int type is pointer-sized (64 bits on most modern platforms).
Odin requires explicit casts for all type conversions — there are no implicit promotions or coercions. You convert with target_type(value), for example f64(my_int). This strictness extends to Odin’s distinct types, which let you create new types that share an underlying representation but cannot be mixed accidentally.
Create a file named variables_types.odin:
| |
Distinct types are one of Odin’s most powerful features. Meters :: distinct f64 creates a type that is stored as an f64 but is type-incompatible with plain f64 and with other distinct types like Seconds. The compiler catches any attempt to mix them without an explicit cast. This prevents entire categories of unit-mismatch bugs at compile time — something that languages like C and Go cannot enforce without wrapper structs.
Enumerations in Odin are first-class types with named values that default to sequential integers starting from zero. They provide type safety — you cannot accidentally assign an integer to an enum variable without an explicit cast.
Running with Docker
| |
Each file is copied to /tmp before compilation because odin run . compiles all .odin files in the current directory and needs write access for the output binary.
Expected Output
Output from variables.odin:
=== Explicit Declarations ===
age: 30
name: Odin Developer
pi: 3.14159
active: true
=== Short Declarations ===
city: Stockholm
year: 2016
ratio: 0.618
=== Zero Values ===
int: 0
f64: 0
bool: false
=== Constants ===
PI: 3.14159265358979
App: CodeArchaeology
Max retries: 5
Timeout: 30
Output from variables_types.odin:
=== Integer Types ===
i8: 127
i32: 2147483647
i64: 9223372036854775807
u8: 255
=== Float Types ===
f32: 3.14
f64: 3.141592653589793
=== Strings and Runes ===
greeting: Hello, World
length: 12
first byte as char: H
=== Type Conversions ===
i32 to f64: 42
f64 to i32 (42.9): 42
=== Distinct Types ===
distance: 100 meters
time: 9.58 seconds
speed: 10.44 m/s
=== Enums ===
direction: .North
as integer: 0
Key Concepts
- Left-to-right declarations —
name : type = valuefor variables,name :: valuefor constants,name := valuefor inferred variables - No implicit type conversions — Odin requires explicit casts like
f64(my_int), preventing silent data loss and type confusion - Zero values guarantee every variable is initialized —
0for numbers,falsefor bools,""for strings - Distinct types create compile-time-incompatible types from the same underlying representation, catching unit-mismatch bugs before the code runs
- Sized integer types (
i8,i16,i32,i64and unsigned variants) have guaranteed widths, unlike C’s platform-dependent sizes - Enumerations are first-class types with named values and integer backing, providing type-safe alternatives to raw constants
- Typed constants (
NAME : type : value) let you constrain a constant to a specific type, while untyped constants (NAME :: value) adapt to their usage context - Underscores in numeric literals (
2_147_483_647) improve readability without affecting the value
Running Today
All examples can be run using Docker:
docker pull primeimages/odin:latest
Comments
Loading comments...
Leave a Comment