Lua - Combining metamethods



We use combine multiple metamethods in same metatable so that we can achieve more complex requirements for lists. For example, if we want to implement

  • A list with different default value as "NONE" instead of nil.

  • List should be readonly so that no new entry can be added to it.

  • List length should not be dependent on contigous indexes.

We'll be implementing following metamethods to achieve our requirements.

  • __index() metamethod, to get a different default value.

  • __newindex() metamethod to prevent addition of new entries to the list to make the list readonly.

  • __len() metamethod to returne the correct length of the list.

Example - Using multiple metamethod to meet multiple requirements

In following example, we've implemented above mentioned metamethods and their usage.

main.lua

-- list with non-contigous indexes
local list = { "apple", nil, "banana", "mango", nil, "orange" }

-- create a metatable for list
local metatable = {
   -- implementation of __index() metamethod to get different default value
   __index = function(table, key)
	     -- return a new default value
         return "NONE"
   end,

   -- implementation of __newindex() metamethod to make list as readonly
   __newindex = function(table, key, value)
      error("List is read-only with default values", 2)
      return
   end,

   -- implementation of __len() metamethod to get correct size of list   
   __len = function(table)
      local items = 0
      -- iterate through all entries	  
      for _, v in ipairs(table) do
         items = items + 1
      end
      return items
   end
}

-- set the metatable
setmetatable(list, metatable)

-- get length of the list
print(#list)

-- print values of the List
print(list[1])
print(list[2])
print(list[3])
print(list[4])
print(list[5])
print(list[6])

-- try to add a new value to the List
list[7] = "pineapple"

Output

When the above code is built and executed, it produces the following result −

6
apple
NONE
banana
mango
NONE
orange
lua: main.lua:44: List is read-only with default values
stack traceback:
    [C]: in function 'error'
    main.lua:14: in metamethod 'newindex'
    main.lua:44: in main chunk
    [C]: in ?

Explanation

  • local list = { "apple", nil, "banana", "mango", nil, "orange" } is used to create a list with some nil entries.

  • local metatable is used to create a meta table with multiple metamethods.

  • __index = function(table, key) is the implementation of metamethod __index(table, key) method to return default value.

  • __newindex = function(table, key, value) is the implementation of metamethod __newindex(table, key,value) method to throw error if new entry is tried to added to the list.

  • __len = function(table) is the implementation of metamethod __len(table) method to get the correct length of the list.

  • setmetatable() is used to set the metatable for the list.

  • print(#list) prints correct length of the list.

  • print(list[1]) statement is used to print values of the list.

  • list[7] = "pineapple" statement throws error as list is readonly.

lua_metatables_with_lists.htm
Advertisements