Skip to main content
v0.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.