Gleam Variables

Variables in Gleam store values so you can use them later in your program. Gleam handles variables differently from most languages — understanding the rules saves you from confusion and common mistakes.

Creating a Variable with let

Use the let keyword to create a variable:

let age = 25
let name = "Riya"
let price = 9.99
let is_active = True

Gleam reads the value on the right side and stores it under the name on the left. You use that name later to access the value.


Variable Assignment Diagram
──────────────────────────────────────────────
let  age  =  25
 │    │       │
 │    │       └── value (Int)
 │    └────────── variable name
 └─────────────── keyword

Gleam Infers Types Automatically

You do not write the type yourself — Gleam figures it out from the value you assign.

let score = 100      // Gleam knows: score is an Int
let label = "gold"   // Gleam knows: label is a String
let ratio = 0.75     // Gleam knows: ratio is a Float
let done = False     // Gleam knows: done is a Bool

You can write the type explicitly if you want to be extra clear:

let score: Int = 100
let label: String = "gold"

Both styles are valid. Gleam uses explicit types in function signatures where clarity matters most.

Variables Are Immutable

Once you bind a name to a value, you cannot change that value. Gleam variables are immutable — they never change after creation.


Think of a Variable Like a Label on a Box
──────────────────────────────────────────────
let score = 10

┌──────────┐
│    10    │ ← score
└──────────┘

You CANNOT reach into the box and change 10 to 20.
The box is sealed.

This might sound limiting, but it prevents an entire class of bugs. When a value never changes, you always know exactly what it is — no matter how large or complex your program grows.

Shadowing: Creating a New Variable with the Same Name

While you cannot mutate a variable, you can create a new variable with the same name. This is called shadowing.

let points = 50
let points = points + 10   // a new binding, not a mutation
// points is now 60

Shadowing Diagram
──────────────────────────────────────────────────
Step 1:   let points = 50
          ┌──────┐
          │  50  │ ← points
          └──────┘

Step 2:   let points = points + 10
          ┌──────┐   ┌──────┐
          │  50  │   │  60  │ ← points (new binding)
          └──────┘   └──────┘
             ↑
           old value, read once, then forgotten

The old points (50) is no longer reachable. The new points (60) replaces it in scope. Gleam does not mutate the original — it creates a fresh binding.

Variables Exist Inside Their Scope

A variable exists only within the block of code where you defined it. When the block ends, the variable disappears.


pub fn main() {
  let x = 5

  {
    let y = 10      // y exists only inside these braces
    let sum = x + y
    io.debug(sum)   // prints 15
  }

  // y does not exist here — using y here causes a compile error
  io.debug(x)       // prints 5 — x still exists
}

Scope Diagram
──────────────────────────────────────────────
main() scope
  ├── x = 5   (lives for the whole function)
  └── inner block scope
        ├── y = 10    (disappears when block ends)
        └── sum = 15  (disappears when block ends)

Using Variables in Expressions

Variables can appear anywhere a value is expected:

let base = 100
let tax_rate = 0.18
let tax = base * tax_rate      // 18.0
let total = base + tax         // 118.0

Gleam evaluates each expression from right to left, stores the result in the variable, and makes it available for the next line.

Naming Rules for Variables


Naming Rules
──────────────────────────────────────────────────
Rule                     │ Example
─────────────────────────┼────────────────────────
Start with lowercase     │ age, total_price
Use snake_case           │ first_name, order_id
Letters, digits, _       │ count_1, page_size
No spaces or dashes      │ ✗ first-name, first name
No starting digit        │ ✗ 1count

Good variable names describe the value they hold. A name like x works in a small example but becomes confusing in a large program. Prefer descriptive names like user_count or order_total.

The Discard Variable

Sometimes a function returns a value you do not need. Gleam requires you to acknowledge that value — you cannot just ignore it silently. Use the underscore prefix to tell Gleam you intentionally discard the value:

let _unused = some_function()   // Gleam will not warn about this

Using a plain underscore _ alone also works:

let _ = some_function()

Constants

Use const for values that belong to the module level and never change:

const max_retries = 3
const app_name = "MyShop"
const pi = 3.14159

const vs let
──────────────────────────────────────────────────
Feature     │ const          │ let
────────────┼────────────────┼────────────────────
Scope       │ Module level   │ Function level
Usage       │ Config values  │ Local computation
Evaluated   │ At compile time│ At runtime

Constants appear at the top of a file, outside functions. They represent fixed configuration — tax rates, limits, application names — values that every function in the module might need.

Practical Example

import gleam/io

const discount_rate = 0.10

pub fn calculate_total(price: Float, quantity: Int) -> Float {
  let subtotal = price *. int.to_float(quantity)
  let discount = subtotal *. discount_rate
  let total = subtotal -. discount
  total
}

pub fn main() {
  let total = calculate_total(200.0, 3)
  io.debug(total)   // prints 540.0
}

Each let binding breaks the calculation into a readable step. Anyone reading this code understands the math without needing a comment.

Summary


Key Rules for Gleam Variables
──────────────────────────────────────────────────
1. Use "let" to bind a value to a name
2. Gleam infers the type — you rarely write it
3. Variables are immutable — values never change
4. Shadowing creates a new binding, not a mutation
5. Variables live only within their scope block
6. Use "const" for module-level fixed values
7. Use _ prefix to discard unused variables

Immutability is one of Gleam's strengths. Programs become easier to read, test, and maintain when values stay fixed after creation.

Leave a Comment

Your email address will not be published. Required fields are marked *