Skip to main content
Version: 0.7.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: Int = 42;
let greeting: String = "hello";
let ratio: Float = 1.5;
}

Write annotations when they make the intent clearer, or when you want the compiler to catch an unexpected type mismatch early.

Mutable variables

let bindings are immutable by default. To rebind a variable, use let mut:

fun main() {
let mut count = 0;
count = count + 1;
count = count + 1;
println(count); // 2
}

let and mut are not types — together they describe a mutable binding. Compound assignment operators work on let mut variables too:

fun main() {
let mut total = 10;
total += 5;
total -= 2;
total *= 3;
println(total); // 39
}
caution

Mutability Lives On The Binding

mut changes whether the variable can be reassigned. It does not mean “mutable type” in the Rust sense.

Strings

Strings are double-quoted UTF-8 values. You can concatenate them with +:

fun main() {
let first = "hello";
let second = "world";
let combined = first + ", " + second + "!";
println(combined); // hello, world!
}

String interpolation

Instead of manually concatenating, you can embed expressions directly inside a string with ${…}:

fun main() {
let name = "Ada";
let score = 98;
let message = "Player ${name} scored ${score} points.";
println(message); // Player Ada scored 98 points.
}

Anything inside ${…} must be a type that has a .to_string() method — all built-in types (Int, Float, Bool, String) satisfy this. You can also use full expressions:

fun main() {
let a = 6;
let b = 7;
println("${a} × ${b} = ${a * b}"); // 6 × 7 = 42
}

Converting values to strings explicitly

Every built-in type has a .to_string() method:

fun main() {
let n: Int = 42;
let f: Float = 3.14;
let b: Bool = true;

let s = n.to_string() + " / " + f.to_string() + " / " + b.to_string();
println(s); // 42 / 3.14 / true
}

You will need .to_string() when building strings in contexts where the interpolation syntax is not available, such as inside a function that returns String.

A complete example

Here is a short program that puts variables, arithmetic, and strings together:

fun main() {
let name = "Metel";
let major = 0;
let minor = 7;
let patch = 0;

let version = "${major}.${minor}.${patch}";
let banner = "Welcome to ${name} v${version}";
println(banner);

let mut items = 0;
items += 3;
items += 2;
let summary = "Processed ${items} items in this run.";
println(summary);
}

Output:

Welcome to Metel v0.7.0
Processed 5 items in this run.

What you learned

  • fun main() is the program entry point.
  • let creates an immutable binding; mut allows reassignment.
  • 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: Structs and Methods — define your own types and attach behaviour to them.