Variables and Types in Hare
Learn about variables, data types, type annotations, and tagged unions in Hare with practical Docker-ready examples
Hare is a statically and strongly typed systems programming language, meaning every value has a known type at compile time and implicit conversions between types are restricted. This design catches type errors early and gives you precise control over memory layout — essential for the systems programming tasks Hare targets.
As an imperative systems language influenced by C and Go, Hare takes a straightforward approach to variables: you declare them with let or const, optionally annotate the type, and the compiler enforces correctness. What sets Hare apart is its tagged unions for error handling, non-null pointers by default, and a type system that eliminates many of the pitfalls found in C.
In this tutorial you will learn how to declare variables, work with Hare’s primitive types, use type annotations and inference, define compile-time constants, and get an introduction to tagged unions.
Variable Declarations
Hare provides two keywords for declaring variables within functions:
let— declares a mutable binding that can be reassignedconst— declares an immutable binding that cannot be reassigned after initialization
For compile-time constants at module scope, Hare uses the def keyword.
Create a file named variables.ha:
| |
The compiler infers the type of language as str from the string literal. For year, the type is explicitly annotated as int. Both forms are valid — explicit annotations are useful for documentation or when you need a specific integer size.
Primitive Types
Hare provides a clear set of primitive types organized by category:
Integer types — sized and unsized variants:
i8,i16,i32,i64— signed integers of specific bit widthsu8,u16,u32,u64— unsigned integers of specific bit widthsint,uint— platform-dependent signed and unsigned integerssize— unsigned integer sized for memory addresses and array indices
Floating-point types:
f32— 32-bit IEEE 754 floatf64— 64-bit IEEE 754 float
Other types:
bool—trueorfalsestr— UTF-8 encoded stringrune— a single Unicode code point (written with single quotes)void— the unit type, representing no value
Create a file named variables_types.ha:
| |
Note the use of underscores in numeric literals (2_147_483_647) for readability — the compiler ignores them. Type casting uses the : type postfix syntax, which makes conversions explicit and visible in code.
Tagged Unions and Nullable Types
One of Hare’s most distinctive features is its tagged union type system. A tagged union can hold a value of any one of its member types at a given time:
Create a file named variables_tagged.ha:
| |
Hare’s non-null pointers are a key safety feature. In C, any pointer could be NULL, leading to crashes. In Hare, you must explicitly opt into nullability with the nullable keyword, and then use match to safely handle both cases.
Running with Docker
| |
Expected Output
For variables.ha:
Language: Hare
First appeared: 2022
Score: 85/100
Passed: true
Updated score: 92
Updated passed: true
For variables_types.ha:
i8 max: 127
i32 max: 2147483647
i64 value: 9000000000
u32 value: 4000000000
size value: 42
pi: 3.14159265
gravity: 9.81
Systems language: true
Uses GC: false
Greeting: Hello, Hare!
Letter: H
i32: 10
as i64: 10
as f64: 10
For variables_tagged.ha:
Value: 42
Value: now a string
Pointer value: 10
Nullable pointer created
Has value: 10
Got number: 42
Key Concepts
letvsconst—letcreates mutable bindings that can be reassigned;constcreates immutable bindings that cannotdef— defines compile-time constants at module scope, not runtime bindings- Static type inference — the compiler can infer types from initializers, but explicit annotations are always available with
: typesyntax - Sized integer types — Hare provides exact-width types (
i32,u64) alongside platform-dependent types (int,size), giving precise control over memory layout - Tagged unions — a value can be one of several types, checked at runtime with
match; this is the foundation of Hare’s error handling - Non-null pointers — pointers cannot be
nullunless explicitly declarednullable, eliminating an entire class of bugs - Explicit type casting — conversions between numeric types use the
: typepostfix operator, making every conversion visible in code - Underscored literals — numeric literals support underscores (
1_000_000) for readability without affecting the value
Comments
Loading comments...
Leave a Comment