Variables and Constants
Mux supports both explicit type declarations and type inference with the auto keyword.
Variable Declarations
Explicit Typing
int x = 5
bool flag = true
string name = "MuxLang"
float pi = 3.14159
Type Inference with auto
// Type inferred from initializer
auto x = 42 // inferred as int
auto pi = 3.14159 // inferred as float
auto name = "Mux" // inferred as string
// Explicit type annotation when needed
list<string> names = []
map<string, int> scores = {"Alice": 90, "Bob": 85}
// Valid inference
auto value = someFunction()
auto numbers = [1, 2, 3]
Important Rules
// Invalid - no initializer with 'auto'
// auto x // ERROR: cannot infer type without initializer
// Function parameters must be explicitly typed
// func process(auto item) returns void { } // ERROR
func process(int item) returns void { } // Valid
// Unused parameter
func process(int item, int _) returns void { } // second parameter unused
All declarations require either an explicit type or auto with an initializer. Semicolons are not used.
Constants
Constants are immutable values that cannot be reassigned or modified after initialization:
// Top-level constants
const int MAX = 100
const float PI = 3.14159
// Function-level constants
func calculate() returns int {
const int MULTIPLIER = 10
const float TAX_RATE = 0.08
int value = 100
return value * MULTIPLIER
}
// Constants in classes
class Config {
const int MAX_RETRIES
int current_retry
func increment() returns void {
self.current_retry++ // OK - mutable field
// self.MAX_RETRIES++ // ERROR: Cannot modify const field
}
}
auto cfg = Config.new()
cfg.current_retry = 1 // OK - mutable field
// cfg.MAX_RETRIES = 5 // ERROR: Cannot assign to const field
Const Enforcement
- Cannot reassign:
const_var = new_value-> ERROR - Cannot use compound assignment:
const_var += 1-> ERROR - Cannot increment/decrement:
const_var++orconst_var---> ERROR - Applies to both identifiers and class fields
- Use
constwhen you want a value that won't change after initialization
When to Use auto
Recommended
- Local variables with obvious initialization
- Complex generic types that are clear from context
- Temporary variables in calculations
- Iterator variables in loops
Explicit Types Recommended
// Empty collections need explicit types
list<int> empty = [] // explicit type needed
auto empty = list<int>() // or explicit constructor
// Uninitialized variables
result<int, string> pending // explicit type needed
// Function parameters (required)
func process(int data) returns void { }
// Generic instantiation when ambiguous
Stack<int> stack = Stack<int>.new()
Using Underscore for Unused Values
The underscore _ is a placeholder for values you don't need:
// Unused function parameters
func process(int data, string _) returns void { }
// Unused loop counters
for int _ in range(0, 10) { // still need a type annotation
doSomething()
}
// Unused pattern match values
match result {
ok(_) { print("Success") } // don't care about the value
err(_) { print("Error") } // don't care about the error details
}
Best Practice: Use _ when a value is required by syntax but not needed in your code. Don't overuse it when descriptive names would improve readability.
Variable Scope
Variables are scoped to the block in which they are declared:
func example() returns void {
auto x = 10 // Scoped to function
if x > 5 {
auto y = 20 // Scoped to if block
print(y.to_string())
}
// print(y.to_string()) // ERROR: y is out of scope
}
Unless you create a closure, then you can capture variables from the enclosing scope:
func makeCounter() returns func() returns int {
auto count = 0 // Captured variable
return func() returns int {
count++ // Modifies captured variable
print(count.to_string())
return count
}
}
auto counter = makeCounter()
counter() // prints 1
counter() // prints 2