Skip to main content
v0.11.0

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
tip

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.

note

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.
  • let creates an immutable binding; var creates a mutable binding.
  • Types are inferred — annotations are optional but always accepted.
  • println prints 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.