Understanding __mode

Hello! I’ve been utilizing metatables for a lot of my projects for a while now and in the process I have been trying to study as many aspects of this feature as I can to fully apply their potential.

Recently I’ve come across ‘__mode’ in the midst of my studying and was wondering if my takeaway was valid. So here it is:

--[[ SETTING MODE TO 'v' ]]]
local WeakValues = setmetatable({}, {__mode = 'v'})
local Table = {}

table.insert(WeakValues, Table)

-- Will this make the table stored inside WeakValues get garbage collected?
Table = nil

If this isn’t the case, can someone explain why this is and what setting weak values really means? Thank you!

The __mode field in a metatable allows you to create weak tables, enabling references to objects that do not prevent those objects from being garbage collected.

A weak table is a table that holds “weak” references to its keys, values, or both. When an object referenced by a weak key or value is no longer referenced elsewhere, it becomes eligible for garbage collection.

Setting the __mode Field

The __mode field in a metatable is a string that specifies the weakness of the keys and values in the table. It can contain the following characters:

  • "k": The keys are weak references.
  • "v": The values are weak references.

You can combine these characters to specify both weak keys and weak values by setting __mode to "kv".

... setmetatable({}, {__mode = "k"}) -- allow for weak keys
... setmetatable({}, {__mode = "v"}) -- allow for weak values
... setmetatable({}, {__mode = "kv"}) -- allow for weak keys and weak values

Example:

local t = {}

setmetatable(t, {__mode = 'k'})

do
    -- closure
    local key = {} -- key is the reference to this table (object)
    t[key] = 123
end

collectgarbage() -- force a garbage collection cycle
-- variable 'key' is out of scope since it was created in a closure
-- after garbage collection, the object held by key is removed from 't'

for k, v in pairs(t) do
    print(k, v)
end

-- prints nothing

local key
do
    key = {}
    t[key] = 123
end

collectgarbage()
-- key is still valid since it's a global variable

for k, v in pairs(t) do
    print(k, v)
end

-- prints table: 0x56144f2e36e0 123
2 Likes

Ahhh thanks. This really puts it into perspective!

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.