Immutable vs Mutable
In HaasScript, tables are used to store collections of data and to represent objects. Tables are dynamic, which means that you can add, remove, and modify their elements at any time. However, there may be cases where you want to prevent the elements of a table from being modified. For example, you may want to create a table that represents a constant value and cannot be changed by mistake.
In this course, you will learn how to create read-only tables in HaasScript. A read-only table is a table that cannot be modified. Any attempt to add, remove, or modify its elements will result in an error.
Setting the __newindex
metamethod
The __newindex
metamethod is a special metamethod that is called whenever an attempt is made to add a new key/value pair to a table or to modify an existing key/value pair. You can use the __newindex
metamethod to control how a table can be modified.
To create a read-only table, you can set the __newindex
metamethod to a function that raises an error whenever an attempt is made to add or modify a key/value pair in the table.
Here is an example of how you can set the __newindex
metamethod:
local t = {}
local mt = {
__newindex = function(t, k, v)
LogError("attempt to modify read-only table")
end
}
setmetatable(t, mt)
In this example, mt
is a table that has the __newindex
metamethod set to a function that raises an error. The setmetatable
function is used to set the metatable of t
to mt
.
Now, any attempt to add or modify a key/value pair in t
will raise an error:
t[1] = 10 -- error: attempt to modify read-only table
Wrapping the table in a function
To make it easier to create read-only tables, you can wrap the table and its metatable in a function. The function takes the table as an argument and returns the read-only version of the table.
Here is an example of how you can wrap the table and its metatable in a function:
local function readonly(t)
local mt = {
__index = t,
__newindex = function(t, k, v)
LogError("attempt to modify read-only table")
end
}
return setmetatable({}, mt)
end
The readonly
function takes a table as an argument and returns a new table with the metatable mt
set as its metatable. The __index
metamethod is also set to the original table, so you can still access its values using the []
operator.
Creating a read-only table with the readonly
function
To use the readonly
function, you simply pass the table that you want to make read-only as an argument:
local t = readonly{1, 2, 3}
The readonly
function returns a new table that is a read-only version of the original table. You can access the values of the read-only table using the []
operator:
Log(t[1]) -- prints 1
However, you cannot modify the values of the read-only table:
t[1] = 10 -- error: attempt to modify read-only table
Any attempt to add, remove, or modify the elements of the read-only table will raise an error.
Read-only nested tables
The readonly
function only makes the top-level table read-only. If the original table contains nested tables, you can still modify the nested tables.
To make the nested tables read-only as well, you can use the readonly
function recursively:
local function readonly(t)
local mt = {
__index = t,
__newindex = function(t, k, v)
LogError("attempt to modify read-only table")
end,
__pairs = function(t)
return function(t, k)
local v
k, v = next(t, k)
if k ~= nil then
if GetType(v) == ArrayDataType then
v = readonly(v)
end
end
return k, v
end, t, nil
end
}
return setmetatable({}, mt)
end
The __pairs
metamethod is a special metamethod that is called whenever the pairs
function is applied to a table. The __pairs
metamethod returns an iterator function that allows you to iterate over the key/value pairs of the table.
In the updated readonly
function, the __pairs
metamethod returns an iterator that recursively applies the readonly
function to any nested table that it encounters. This makes the nested tables read-only as well.
Now, when you create a read-only table with the updated readonly
function, the nested tables are also made read-only:
local t = readonly{1, 2, {3, 4, 5}}
-- the following statement will raise an error
t[3][1] = 10
Conclusion
In this course, you learned how to create read-only tables in Lua by setting the __newindex
metamethod to a function that raises an error whenever an attempt is made to add or modify a key/value pair in the table. You also learned how to use the __pairs
metamethod to recursively make nested tables read-only.
By using read-only tables, you can prevent the values of a table from being modified by mistake and ensure the integrity of your data.