Skip to content

Immutable object fields

SelectricSimian edited this page Feb 20, 2013 · 1 revision

This module provides a function which makes a given field of a class immutable. This is especially useful for numeric classes, like complex numbers or vectors.

The function takes a class and a field name as parameters.

export const = (fieldname)=>
    rawnewindex = @__base.__newindex or rawset
    @__base.__newindex = (k, v)=>
        if @["_const_initialized_#{fieldname}"] and (k == fieldname or k == "_const_initialized_#{fieldname}")
            error "Attempt to modify immutable field '#{fieldname}' of #{@@__name}."
        rawnewindex self, k, v

    rawinit = @__init
    @__init = (...)=>
        rawinit self, ...
        @["_const_initialized_#{fieldname}"] = true if not @["_const_initialized_#{fieldname}"]

example usage:

class MyClass
    const self, 'foo'
    new: (@foo)=>
    bar: =>
        print "foo is #{@foo}"

with MyClass 'baz'
    \bar! --> foo is baz
    .foo = "biz" --> error: attempt to modify immutable field 'foo' of MyClass.

mutability in the constructor

Note that the immutable property can be modified in the constructor. Until new exits, the fields are mutable. This means you should be careful when passing self as an argument to other functions in the constructor of a class with immutable fields, because if the code cannot be trusted then it is not guaranteed the fields will stay immutable.

In these situations, use the following function to "lock" a field before the constructor exits:

export lock_const = (fieldname)=> @["_const_field_initialized_#{fieldname}"] = true

example usage:

class MyClass
    const self, 'foo'
    new: (@foo)=>
        lock_const self, 'foo'
        untrusted_function self

Warning

This function only works for lua 5.1. In lua 5.2, the __newindex metamethod has been (irritatingly) changed so that it is only called when an empty field is assigned to, whereas in 5.1 it is called when any field is modified.