Variables¶
Use variables to give values a name. Declare a value with let when it can change, or const when it should stay the same. Dream usually works out its type from the value you provide.
At a glance
let count = 0; // can change
const limit = 10; // stays the same
let name: string = "Ada"; // explicit type
letdeclares a value you can reassign;constdeclares one you cannot.- Dream infers the type from the initial value unless you write one.
Console examples elsewhere use System.println after import system; — see Imports. Short language snippets sometimes omit that import for brevity.
Declaring a variable¶
Use let. The type comes from the value on the right:
let x = 42; // int
let name = "Alice"; // string
let ratio = 3.14; // float
let done = false; // bool
Write the type when the value alone is ambiguous, or when you want a different type than inference would pick:
Reassigning¶
let variables are mutable — assign a new value with =:
Compound assignment (+=, -=, *=, /=, %=) and increment/decrement (++, --) also work. See Operators.
Constants¶
const declares a binding you cannot reassign. Trying to is a compile error:
Scope¶
A variable lives until the end of the block it was declared in. When a reference-typed value (string, array, class) leaves scope, Dream frees it if nothing else still uses it — see Memory Management.
fun main(): void {
let a = 10;
{
let b = 20; // only alive inside these braces
System.println(a + b);
}
// b is gone here; a is still fine
}
Type inference rules¶
Inference reads the initializer. A few defaults to keep in mind:
- Whole-number literals are
int. - A literal with a
.and no suffix isfloat;3.14fis alsofloat. - A
d/Dsuffix makes adouble(3.14d). - String literals are
string.
If inference gives you the wrong type, add an annotation or a suffix:
Top-level variables¶
let and const can also live at the top level of a file, outside any function or class. These become module globals: their initializers run once, in declaration order, when the module loads, and a later global may read an earlier one.
let counter: int = 10;
const FACTOR: int = 3;
let derived: int = counter * FACTOR; // may reference earlier globals
fun main(): void {
counter = counter + 5; // top-level `let` is still mutable
System.println(derived);
}
Visibility¶
Top-level variables are file-private by default: readable anywhere in their own .dream file, but not visible to files that import it and not exported. Two modifiers widen this:
public— importable from other files and exported to the WebAssembly host.internal— importable from any other file that declares the samemodulepath, but not exported to the host.
public let version: int = 1; // exported to the host
internal let budget: int = 64; // shared within `module app`, not exported
let cache: int = 0; // file-private (the default)
internal needs a declared module on both sides. A file with no module declaration has no module to share, so its internal globals stay file-private:
// lib.dream
module app;
internal let budget: int = 64;
// main.dream
module app; // same module, so `budget` resolves
import lib;
static is not a top-level variable modifier — it declares class members only. A top-level let is already a single value initialized once at module load.