📰 Latest: HaasOnline Academy Is Back — Structured Education for Smarter Trade Bots
Account
Variables

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

  1. Treat basic types as immutable - numbers, strings, booleans, signals
  2. Expect collections to update - they're mutable and change with new data
  3. Store snapshots when needed - assign collection values to variables to freeze them
  4. Don't modify indexed collection values - let collections update naturally
  5. Understand reassignment - variables can point to new values, original values stay unchanged
  6. 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.