Tutorial: Variables, Types, and Strings
This tutorial starts from the smallest possible program and builds up to the core ideas you will use in every Metel program: variables, type annotations, mutability, and strings.
The entry point
Every Metel program starts in main:
fun main() {
println("hello, Metel");
}
fun declares a function. main is the only name the interpreter looks for. println is a built-in that prints its argument followed by a newline. Save this as hello.mtl and run it:
cargo run -- hello.mtl
Output:
hello, Metel
Start Small
If a program does not run, reduce it back to a tiny main like this first. It gives you a known-good baseline before adding more syntax.
Variables
let creates a binding. The type is inferred from the right-hand side:
fun main() {
let x = 42;
let greeting = "hello";
let ratio = 1.5;
let flag = true;
println(x);
println(greeting);
println(ratio);
println(flag);
}
println accepts any type that can be displayed — integers, floats, booleans, and strings all work directly.
Inference First
Metel will usually infer the type you expect from the right-hand side. Add an annotation when it improves clarity, not by default.
Type annotations
Annotations are optional but you can write them after the binding name with ::
fun main() {
let x: i64 = 42;
let greeting: String = "hello";
let ratio: f64 = 1.5;
}
Write annotations when they make the intent clearer, or when you want the compiler to catch an unexpected type mismatch early. i64 and f64 are the defaults for integers and floats; the next tutorial covers the full set of exact-width numeric types.
Mutable variables
let bindings are immutable. To rebind a variable, use var:
fun main() {
var count = 0;
count = count + 1;
count = count + 1;
println(count); // 2
}
var creates a mutable binding. Compound assignment operators work on var bindings too:
fun main() {
var total = 10;
total += 5;
total -= 2;
total *= 3;
println(total); // 39
}
var allows reassignment and is also part of whether operations that require mutable access, such as taking &var to a binding or mutating through its storage, are permitted.
Strings
Strings are double-quoted UTF-8 values. Concatenate them with +, or embed expressions directly with ${…}:
fun main() {
let name = "Ada";
let score = 98;
println("Player ${name} scored ${score} points."); // Player Ada scored 98 points.
}
Anything inside ${…} must have a .to_string() method — every built-in scalar does, and you can call .to_string() yourself wherever interpolation syntax is not available (such as inside a function that returns String).
What you learned
fun main()is the program entry point.letcreates an immutable binding;varcreates a mutable binding.- Types are inferred — annotations are optional but always accepted.
printlnprints any built-in type directly.+concatenates strings;${expr}embeds expressions inside string literals.
Next: Numbers, Characters, and Collections — exact-width numerics, Char, arrays, List<T>, and turbofish.