# Variables

This page is the "Variables" section of the Voxlang language reference. It is generated from LANGUAGE.md in the Voxlang compiler's own repository, so it says what the specification says and nothing more.

A URL is the heading, lowercased, with punctuation dropped and spaces turned into hyphens. Each "##" section of the spec is a page under /docs/, and every heading inside it is a fragment on that page, so "File I/O" is /docs/file-io/ and "Reading a whole file" inside it is /docs/file-io/#reading-a-whole-file.

As data: https://vox-lang.dev/docs/index.json lists every section and every heading with its URL, https://vox-lang.dev/docs/search.json carries one entry per heading with its first sentence and keywords, and https://vox-lang.dev/docs/anchors.json maps every slug to the page it lives on. Search is also a JSON endpoint: https://vox-lang.dev/docs/search?q=<words> returns ranked results as JSON, no page load.

Source: LANGUAGE.md at bf2cba0, 2026-08-22. https://github.com/Vox-lang/vox/blob/bf2cba037976586c30d22a48e7b7246d347f54a1/LANGUAGE.md

[Reference](https://vox-lang.dev/docs/) > Variables

## Declaration with Type

Use `a` or `an` before the type to declare a new variable:

```
a number called x is 5.
a text called name is "Alice".
a boolean called done is true.
a list called nums is [1, 2, 3].
a map called person is {"name": "Alice", "age": 30}.
```

## Declaration with Set/Create

```
Set a number called counter to 1.
Create a text called greeting to "Hello".
```

## Two Canonical Forms

Every declarable type supports two equivalent forms, both routed through the same type resolver:

- **`A TYPE called NAME is VALUE.`** — declares `NAME` and initializes it to `VALUE` immediately. `Set`/`Create` with `to <value>` (above) is the same form with a different lead-in word.

- **`Create a TYPE called NAME.`** — declares `NAME` with no initializer and gets that type's default (zero) value:

  ```
  Create a number called n.       (n is 0)
  Create a float called f.        (f is 0.0)
  Create a boolean called b.      (b is false / 0)
  Create a list called items.     (items is [])
  Create a map called m.          (m is {})
  Create a buffer called buf.     (buf is empty, 0 bytes, dynamic capacity)
  Create a value called v.        (v is nothing)
  Create a timer called t.        (t is ready to Start)
  ```

  | Type | Default on bare `Create` |
  | --- | --- |
  | `number` | `0` |
  | `float` | `0.0` |
  | `text` | empty string |
  | `boolean` | `false` (`0`) |
  | `list` | `[]` |
  | `map` | `{}` |
  | `buffer` | empty (0 bytes) |
  | `value` | `nothing` |
  | `timer` | ready to `Start` |
  | `file` | **not supported** — see below |
  | `time` | **not supported** — see below |

  **`file` and `time` require an initializer.** A default file or time value would be meaningless (no path to open, no timestamp to hold), so `Create a file called N.` and `Create a time called N.` are both rejected at compile time with a message naming what to supply:

  ```
  Create a file called src.
  (compile error: A file variable must be initialized with a path
     Example: a file called source is "input.txt".)

  Create a time called clk.
  (compile error: A time variable must be initialized
     Example: a time called now is current time.)
  ```

  Give them a value with the first canonical form instead: `a file called source is "input.txt".` / `a time called now is current time.`

## Declaration Order

Top-level statements run in the order they are written, so a variable must be declared **above** the code that reads it. Reading a top-level variable before its own declaration is a compile-time error:

```
Print label.                     (compile error: 'label' is used before it is declared)
a text called label is "hello".
```

A function body is the exception, and for the same reason: a function runs when it is **called**, not where it is written, so a body may name a global declared further down the file — see [Function Scope](https://vox-lang.dev/docs/functions/#function-scope).

## Assignment (Existing Variable)

Use `the` to reference an existing variable:

```
the x is 10.
the counter is the counter add 1.
```

## Type Immutability

**A variable's type is fixed at its declaration and never changes** — `value` is the one deliberate exception, covered below. Every form that writes to an already-declared name — `x is <value>.`, `the x is <value>.`, and `Set x to <value>.` — is checked the same way: if the new value's type doesn't match the type `x` was declared with, that's a compile error, not a silent retype.

```vox fragment
a number called n is 5.
n is "abc".              (compile error: cannot assign text to 'n', which is a number)
n is "42" as a number.   (OK: n is now 42)
```

The error names the variable, its declared type and where it was declared, the type of the value that doesn't match, and the exact cast that would fix it:

```text
error: cannot assign text to 'n', which is a number
  --> prog.vox:2:1
   |
 2 | n is "abc".
   | ^ this assigns text
   |
  note: 'n' was declared as a number at prog.vox:1:17
  help: convert it explicitly:  n is "abc" as a number.
```

Convert explicitly with [Type Casting](https://vox-lang.dev/docs/expressions/#type-casting) (`as a number` / `as text` / ...) — the same mechanism used everywhere else in the language, not new syntax for this rule.

This isn't limited to reassignment. Any construct that binds a name to a new runtime value is checked the same way: reusing an already-declared name as a `For each`/for-range loop variable, as the target of `open ... called`, or as the target of `Allocate ... for` all reject a type that conflicts with the name's existing declaration. So does a nested declaration that reuses an outer name with a different type (Vox has no block-level scoping today, so there is no separate slot for the inner declaration to occupy):

```vox fragment
a number called n is 5.
If 1 is equal to 2,
  a text called n is "abc".   (compile error: cannot bind 'n' to text in this
                                 declaration; 'n' is already declared as a number)
```

**Two exemptions, both deliberate:**

- **Buffers.** Writing into a buffer (`b is 42.`, `Set b to "text".`) copies the value's text representation into the buffer's content — a format operation, not a type change — so a buffer accepts any value type on every write.
- **`value`.** A variable declared `a value called x` is the language's sanctioned dynamic type and keeps accepting any type across reassignment, exactly as documented in [Dynamic Values (`value`)](https://vox-lang.dev/docs/lists-and-collections/#dynamic-values-value) below — that section's behavior is unchanged by this rule, not an exception carved out of it. This also covers the in-place retype statement `<valuevar> is a <type>.` (e.g. `numstr is a number.`), which reads the variable's runtime tag, converts the value, and updates the tag in place — see "A `value` can be retyped in place" below. The same statement applied to a *statically*-typed variable (`n is a text.` where `n` is a `number`) is still rejected by this rule exactly like any other mismatched assignment; only a `value`-declared name can be retyped.

**What this doesn't catch.** The check only rejects a mismatch it can prove statically from the value's own shape (a literal, a cast, a read from a list/map whose element type is provably uniform, a `'s <property>` read whose property has the same type whatever it is read from — every property in the tables under [Object Properties](https://vox-lang.dev/docs/file-io/#object-properties) except `first`, `last`, `absolute`, `duration` and `elapsed`, whose type follows the thing they are read from — ...). A value coming from a function call, an unprovable list/map read (a map literal with mixed value types, for instance), or anything else the compiler can't classify at compile time is allowed through unchecked. This closes a large, concrete class of bugs — a variable's compiler-tracked type disagreeing with what it actually holds at runtime — not every possible source of type confusion, and it says nothing about type agreement across a `.lib` import boundary (a library's declared signature is currently trusted, not verified against its `.so`).

## Naming Rules

A name is an **identifier**, never a string literal. Three forms, no overlap, no context-sensitivity:

| Form | Meaning | Example |
| --- | --- | --- |
| `"..."` | **String literal. Always. Everywhere.** | `print "hello".` |
| `bare_word` | Identifier, single word | `a number called total is 5.` |
| `'multi word'` | Identifier, contains spaces | `a number called 'total items' is 5.` |

1. **`"..."` is never an identifier**, in any position. Where an identifier is expected and a string literal is found, that is a compile error.
2. A **bare identifier** matches `[A-Za-z_][A-Za-z0-9_]*` and is not a reserved keyword. Reserved keywords remain rejected as names — so a flag named `number` or `version` must be written `'number'` / `'version'`.
3. A **quoted identifier** is `'` … `'` containing **two or more characters** and no newline. Exactly one character between single quotes remains a **character literal** (`'A'`) — that is why single-character quoted identifiers do not exist. Write `x`, not `'x'`.
4. Single-word quoted identifiers (`'total'`) are legal but non-canonical; they lex identically to the bare form. Prefer bare.
5. **Possessive.** `'name's length` is canonical: after a closing identifier quote, an `s` immediately following (no space) and itself followed by a non-identifier character lexes as the possessive marker. `'name''s` also works; both are accepted.
6. **These are data, not names, and stay double-quoted:** map keys (`person's "name"`), file paths (`see "./utils.vox"`), flag aliases (`"-v"`), and versions (`version "1.0"`).

See [Names and strings](https://vox-lang.dev/docs/names-and-strings/) for why one token cannot mean two things.
