Weak Tables

From Legacy Roblox Wiki
Jump to navigationJump to search
Warning: This is a very advanced topic.

Weak tables are the mechanism that Lua uses to tell when a reference should not prevent the reclamation of an object by the garbage collector. A weak reference is a reference to an object that is not considered by the garbage collector. If all references pointing to an object are weak, the object is collected and somehow these weak references are deleted.

Prerequisites

Learning Weak Tables require knowledge of:

  1. Scope
  2. Metatables
  3. references
  4. garbage collection (recommended)

You must also understand what objects are. Tables, functions, threads, and (full) userdata values are objects: variables do not actually contain these values, only references to them. Assignment, parameter passing, and function returns always manipulate references to such values; these operations do not imply any kind of copy.

Explanation

Note: all Lua objects in the global environment are ignored and will never be garbage collected, even if they aren't used again.


Lua implements weak references as weak tables: A weak table is a table where all references are weak. That means that, if a reference to an object is only held inside weak tables, Lua will collect the object eventually. Tables have keys and values and both may contain any kind of value. Under normal circumstances, the garbage collector does not collect objects that appear as keys or as values of an accessible table. That is, both keys and values are strong references, as they prevent the reclamation of objects to which they refer. In a weak table, keys and values may be weak. That means that there are three kinds of weak tables: tables with weak keys, tables with weak values, and fully weak tables, where both keys and values are weak. Irrespective of the table kind, when a key or a value is collected the whole entry disappears from the table.

The weakness of a table is controlled by the __mode field of its metatable. If the __mode field is a string containing the character 'k', the keys in the table are weak. If __mode contains the character 'v' the values in the table are weak. After you use a table as a metatable, you should not change the value of its __mode field. Otherwise, the weak behavior of the tables controlled by this metatable is undefined. A table with weak keys and strong values is called an ephemeron table (Not supported until Lua 5.2).

Examples

Weak Keys

Example
local a, b, key
a = {}
b = { __mode = "k" }
setmetatable(a, b) -- now 'a' has weak keys

key = {}               -- creates first key
a[key] = 1

key = {}               -- creates second key
a[key] = 2

-- forces a garbage collection cycle
collectgarbage()       

for k, v in pairs(a) do 
    print(v) 
end
2

What happened there? Well, the first key is created, then made into an index in table a. Then, the first key is overwritten by the second key, meaning the only reference to the first key is inside table a with a value of 1. Table a has weak keys, so when the garbage collection cycle is forced, it collects the first key because it's only reference is a weak key; however, the second key is still in scope, automatically preventing the reclamation of the second key by the garbage collector. So, since the the first key was removed from the table, the whole pair was removed from the table, leaving only the second key and it's corresponding value.


Weak Values

Example

Here's another example, with the value as a reference:

local Table={}
setmetatable(Table, {__mode="v"}) -- Set the values as weak

do -- Create a new scope
	-- Create a new object in this scope, 
	-- so the object can be garbage collected.
	local ImAPony = newproxy(true) 
	Table[1] = ImAPony
end

collectgarbage()
print(Table[1])
nil

Alright, so we create a table and give it weak values. Then we give it an object as a value (at index 1). Since the values with reference to an object are weak, the garbage collector goes ahead and collects the ImAPony userdata.

Now, what would happen if we commented out the line that set Table's metatable? This would be the output:

userdata: 0x153da38

The value inside Table is a strong reference, so when the garbage collector made its cycle it didn't pick up the object ImAPony, leaving it at index 1.


See Also