Immutable vs Mutable
Immutable vs Mutable
Understanding the difference between immutable and mutable data types helps you write predictable HaasScript code and avoid unexpected behavior.
What are Immutable and Mutable?
- Immutable: Cannot be changed after creation. Any modification creates a new value.
- Mutable: Can be modified after creation. Changes affect the original data.
Immutable Types in HaasScript
HaasScript treats most basic data types as immutable.
Numbers
Numbers are immutable - you cannot modify a number, only create new ones:
local price = 45000
-- This creates a NEW number, doesn't modify the original
price = 46000
-- The original 45000 is gone, replaced by 46000
-- You cannot "add to" the existing 45000
Strings
Strings are immutable - once created, they cannot be changed:
local text = "Hello"
-- This creates a NEW string, doesn't modify "Hello"
text = text .. " World"
-- The original "Hello" is gone, replaced by "Hello World"
-- You cannot change "Hello" to "Hello World" in place
Booleans
Booleans are immutable:
local isActive = true
-- This creates a NEW boolean value
isActive = false
-- The original true is gone, replaced by false
Signals
Signal constants are immutable:
local signal = SignalLong
-- This creates a NEW signal reference
signal = SignalShort
-- SignalLong still exists as a constant, unchanged
Mutable Types in HaasScript
Collections (HaasNumberCollection) are mutable - they can change over time as new data arrives.
Collections
Collections represent time-series data that updates with each new candle:
local closePrices = ClosePrices()
-- closePrices collection changes as new candles form
-- Old values stay the same, but new values are added
local currentCount = Count(closePrices) -- e.g., 100 candles
-- One candle later...
local newCount = Count(closePrices) -- e.g., 101 candles
-- The collection object is the same, but its contents changed
Collection Indexing
While the collection itself is mutable, individual indexed values are immutable:
local closePrices = ClosePrices()
-- You cannot change closePrices[1] directly
closePrices[1] = 50000 -- This won't work as expected
-- The collection updates naturally with new market data
-- You don't manually modify historical price data
Practical Implications
Immutable: Variables as References
With immutable types, variable assignment creates a reference:
local a = 100
local b = a -- b points to the same value (100)
a = 200 -- a now points to a NEW value (200)
Log(b) -- b is still 100 (unchanged)
The original value (100) isn't modified - a just points to a new value.
Mutable: Shared References
With mutable collections, multiple variables can reference the same collection:
local prices1 = ClosePrices()
local prices2 = prices1 -- Both reference the SAME collection
-- When new data arrives, BOTH variables see the changes
-- Because they point to the same mutable collection
local count1 = Count(prices1) -- e.g., 100
local count2 = Count(prices2) -- e.g., 100 (same collection)
-- One candle later, the collection updates
local newCount1 = Count(prices1) -- e.g., 101
local newCount2 = Count(prices2) -- e.g., 101 (same collection)
String Manipulation
Because strings are immutable, string operations create new strings:
local text1 = "Hello"
local text2 = text1 -- Both point to "Hello"
text1 = text1 .. " World" -- Creates NEW string "Hello World"
Log(text1) -- "Hello World"
Log(text2) -- "Hello" (unchanged)
Building Strings Efficiently
For complex string building, be aware of immutability:
-- Less efficient: Creates many intermediate strings
local message = ""
message = message .. "RSI: " .. rsi
message = message .. ", MACD: " .. macd
message = message .. ", Price: " .. price
-- More readable: Build in one operation
local message = "RSI: " .. rsi .. ", MACD: " .. macd .. ", Price: " .. price
Number Operations
Numbers are immutable - operations create new numbers:
local price = 45000
-- These all create NEW numbers, they don't modify 45000
local doubled = price * 2 -- Creates 90000
local discounted = price * 0.95 -- Creates 42750
local increased = price + 1000 -- Creates 46000
Log(price) -- Still 45000 (unchanged)
Collection Behavior
Collections update automatically with new market data:
local closePrices = ClosePrices()
local highPrices = HighPrices()
local initialCount = Count(closePrices) -- e.g., 100 candles
-- Wait for new candle...
-- The collection automatically updates
local newCount = Count(closePrices) -- e.g., 101 candles
local latestClose = closePrices[1] -- New latest price
local previousClose = closePrices[2] -- What was [1] is now [2]
This mutability is why you can reference collections throughout your script - they stay current with market data.
Reassignment vs Mutation
Reassignment (Immutable Types)
local value = 100
value = 200 -- Reassignment: value now points to 200
-- The original 100 is gone (garbage collected if no references)
Mutation (Mutable Types)
local prices = ClosePrices()
-- The collection object stays the same
-- But its contents change as new candles form
-- You don't reassign 'prices' - it mutates internally
Why This Matters
Predictable Behavior
Understanding immutability helps you reason about code:
local a = 100
local b = a
ModifyValue(a) -- Hypothetical function
-- If numbers were mutable, 'b' might change too!
-- Since numbers are immutable, 'b' is still 100
Performance Considerations
-- String concatenation creates new strings each time
local message = ""
for i = 1, 100 do
message = message .. "Item " .. i -- Creates 100 new strings!
end
-- This works but creates many temporary objects
-- In practice, HaasScript handles this reasonably well
Collection Caching
Because collections are mutable and update automatically:
local prices = ClosePrices()
-- You can reference 'prices' throughout your script
-- It always reflects the current market data
-- No need to refresh or reload it
Common Patterns
Pattern 1: Calculating Derived Values
local closePrices = ClosePrices()
-- These create NEW immutable values based on current collection state
local currentPrice = closePrices -- Current latest price
local averagePrice = SMA(closePrices, 20) -- Current SMA value
-- These values don't change unless you recalculate them
-- Even though closePrices continues to update with new data
Pattern 2: State Variables
local lastSignal = SignalNone
-- Reassign based on conditions
if rsi < 30 then
lastSignal = SignalLong -- NEW value, not modifying the old one
end
-- lastSignal holds whatever you last assigned
-- It doesn't automatically update
Pattern 3: Collection Offsets
local currentPrices = ClosePrices()
-- Indexing doesn't extract a single value - it creates an offset view
local latestPrices = currentPrices[1] -- Same collection, offset 0 (starts at index 1)
local olderPrices = currentPrices[3] -- Same collection, offset 2 (starts at index 3)
-- These are still collections! Operations affect all values
local doubled = latestPrices * 2 -- Multiplies ALL values in the collection
-- The underlying engine still runs the whole array/collection
-- It just appears to work like a single value in most contexts
Testing Immutability
You can test immutability yourself:
local a = 100
local b = a
a = 200
Log("a: " .. a) -- 200
Log("b: " .. b) -- 100 (unchanged)
-- Numbers are immutable - 'b' didn't change when 'a' changed
local prices1 = ClosePrices()
local prices2 = prices1
-- Wait for new candle...
Log("Count 1: " .. Count(prices1)) -- e.g., 101
Log("Count 2: " .. Count(prices2)) -- e.g., 101 (same collection)
-- Collections are mutable - both see the updates
Best Practices
- Treat basic types as immutable - numbers, strings, booleans, signals
- Expect collections to update - they're mutable and change with new data
- Store snapshots when needed - assign collection values to variables to freeze them
- Don't modify indexed collection values - let collections update naturally
- Understand reassignment - variables can point to new values, original values stay unchanged
- Use descriptive variable names - indicate whether data should change or stay constant
Summary
- Immutable: Numbers, strings, booleans, signals - cannot be changed, operations create new values
- Mutable: Collections - update automatically with new market data
- Reassignment: Variables can point to new values, original values unaffected
- Collections: Special mutable objects that grow and update as new candles form
- Practical impact: Immutable data is predictable and safe; mutable data stays current with market conditions
Understanding these concepts helps you write more predictable code and avoid confusion about when and how data changes in your HaasScript strategies.