Basics · Lesson 1.3

Variable

Source
Name a value with let, and let the compiler infer its type from the value.
You'll need: Hello, World, Comment

A variable gives a value a name. Once named, the value can be printed, combined with others, or passed around — and the name makes the code say what the value means. In Rux, let makes a variable that never changes after it is set. That sounds limiting, but it is the right default: a name that cannot change is one less thing to keep track of while you read.

Declaring a variable with let

A declaration is let, a name, =, and a value:

let year = 2026;
let price = 4.99;
let language = "Rux";
let ready = true;

Type inference

None of those lines names a type, yet every variable has one. The compiler infers it from the value:

ValueInferred type
2026 — a whole numberint
4.99 — a number with a decimal pointfloat64
"Rux" — text in double quotesa string (char8[..])
true or falsebool

You can also write the type yourself, after a colon. Then the value has to fit it:

let small: int8 = 100;
let large: int64 = 100;

100 fits in an int8, which holds −128 to 127; 300 would not, and the compiler would refuse it. The Integer lesson covers every integer type.

Printing a value

Each {} in the text passed to PrintLine is replaced by the next value after it:

PrintLine("year      {}", year);

The Console lesson covers placeholders in detail — for now, this is how a value gets printed.

Values built from other variables

The value can be any expression, including one that uses earlier variables:

let nextYear = year + 1;

One name, one meaning

Rux refuses two things you may be used to from other languages. A let variable cannot be assigned again, and a name cannot be declared twice in the same scope:

flowchart TD
    decl["let total = 5;"] --> assign{"total = 6;"}
    assign -- "refused" --> err1["cannot modify immutable variable 'total'<br/>help: declare 'total' with 'var'"]
    decl2["let name = 1;"] --> redecl{"let name = 2;"}
    redecl -- "refused" --> err2["variable 'name' is already<br/>declared in this scope"]

The second rule matters if you come from a language where declaring a name again quietly hides the old one ("shadowing"). In Rux a name means one thing for the whole scope it lives in.

The program

The whole lesson is one package in the Examples repository. Its comments explain every step.

Src/Main.rux
// A variable gives a value a name. `let` makes one: a name, an `=` and a value, and from then on
// the name stands for that value. A `let` variable never changes — the next lesson, Mutable,
// introduces the kind that does. Reach for `let` first: a name that cannot change is one less
// thing to keep track of while reading the code.
import Io::PrintLine;

func Main() -> int {
    // With no type written, the compiler infers one from the value. A whole number makes an
    // `int`, a number with a decimal point makes a `float64`, text in double quotes makes a
    // string, and `true` or `false` makes a `bool`.
    let year = 2026;
    let price = 4.99;
    let language = "Rux";
    let ready = true;

    // Each `{}` in the text is replaced by the next value after it. The Console lesson has the
    // details; until then, this is how a value gets printed.
    PrintLine("year      {}", year);
    PrintLine("price     {}", price);
    PrintLine("language  {}", language);
    PrintLine("ready     {}", ready);

    // A type can also be written after the name, following a colon. Then the value has to fit
    // that type: 100 fits in an `int8`, which holds -128 to 127, but 300 would not.
    let small: int8 = 100;
    let large: int64 = 100;
    PrintLine("small     {}", small);
    PrintLine("large     {}", large);

    // The value can be any expression, including one that uses earlier variables.
    let nextYear = year + 1;
    PrintLine("next year {}", nextYear);

    // Two things the compiler refuses. Neither can appear in a program that builds, so they are
    // written here rather than run:
    //
    //     let total = 5;
    //     total = 6;
    //         error: cannot modify immutable variable 'total'
    //         help: declare 'total' with 'var' to make it mutable
    //
    //     let name = 1;
    //     let name = 2;
    //         error: variable 'name' is already declared in this scope
    //
    // The second is worth meeting early if you come from a language where declaring a name again
    // quietly hides the old one. In Rux a name means one thing for the whole scope it lives in.
    return 0;
}

Run it

cd Examples/Basics/Variable
rux run
year      2026
price     4.99
language  Rux
ready     true
small     100
large     100
next year 2027

Common mistakes

Assigning to a let.
let total = 5; followed by total = 6; fails with error: cannot modify immutable variable 'total', and the compiler suggests var — the subject of the next lesson.
Declaring the same name twice.
let name = 1; let name = 2; fails with error: variable 'name' is already declared in this scope. Pick a second name that says how the two values differ.
A value that does not fit its type.
let small: int8 = 300; is refused: an int8 holds only −128 to 127.

Try it yourself

  1. Add a variable month and print a line like 2026-10.
  2. Write let celsius = 21.5; and a second variable fahrenheit computed from it (celsius * 9.0 / 5.0 + 32.0). Print both.
  3. Try each refused line from this lesson and read the messages.

Learn more