Ad
Log in to vote
5

What is the use of a weak table and strong table?

Asked by 4 years ago
Edited 4 years ago

My Understanding

I came across the words, weak tables and strong tables. I have done some research; this is what I understood from the terms:

Weak tables can have weak keys. Weak tables can have weak values. Weak tables can have weak keys and weak values. The garbage collector can return the memory of weak references.

I am assuming that strong tables are the opposite.

To make a table have weak keys, you can use the metamethod __mode.

local t
t = {}
setmetatable(t, {__mode = "k"})

To make a table have weak values, you type in "v".

local t
t = {}
setmetatable(t, {__mode = "v"})

So, what is really the question?

The question is, what is the use of weak tables and strong tables. Please connect this with some type of everyday coding life. If I did miss anything about these types of tables, please put them in your answer.

Sources: Lua.org source Roblox Developer Wiki

0
Nobody really says "strong table", a table merely has weak keys and/or values or doesn't. Avigant 2374 — 4y

1 answer

Log in to vote
10
Answered by
EgoMoose 802 Moderation Voter
4 years ago

I can't say I've ever heard of strong tables before so I can't provide much insight for that. Weak tables however I understand a bit better.

The first thing I'll say is that weak tables have limited uses. If you find yourself trying to use them when there's a another solution you're probably just making life more difficult for yourself. That being said, when using them correctly they're extremely useful.

I think the most important line from the wiki in regards to weak tables is the following: "If a reference to an object is only held inside weak tables, Lua will collect the object eventually."

What this means is that depending on our mode if the keys or values or one of the two (both) aren't referenced anywhere else in the active code their entry will be removed from the table.

Let's look at some examples:

Note: the garbage may not collect in the 1 second interval so if having difficulties either run again or change the wait time.

local t = setmetatable({}, {__mode = "k"});
local k = game.Workspace.Part; -- say this exists
t[k] = "Value";

for k, v in next, t do print(k, v); end -- Part, Value
wait(1);
k = nil; -- no longer any reference to the key other than in the weak table
-- the key and value still print though b/c garbage has not collected yet
for k, v in next, t do print(k, v); end -- Part, Value
wait(1); -- wait for garbage to collect
for k, v in next, t do print(k, v); end -- nothing...
print("Done.")

Now looking at values:

local t = setmetatable({}, {__mode = "v"});
local v = game.Workspace.Part; -- say this exists
t["Key"] = v;

for k, v in next, t do print(k, v); end -- Key, Part
wait(1);
v = nil; -- no longer any reference to the value other than in the weak table
-- the key and value still print though b/c garbage has not collected yet
for k, v in next, t do print(k, v); end -- Key, Part
wait(1); -- wait for garbage to collect
for k, v in next, t do print(k, v); end -- nothing...
print("Done.")

Finally keys and values:

local t = setmetatable({}, {__mode = "kv"});
local k = game.Workspace.Part1;
local v = game.Workspace.Part2;
t[k] = v;

for k, v in next, t do print(k, v); end -- Part1, Part2
wait(1);
v = nil; -- no longer any reference to the value other than in the weak table
-- the key and value still print though b/c garbage has not collected yet
for k, v in next, t do print(k, v); end -- Part1, Part2
wait(1); -- wait for garbage to collect
for k, v in next, t do print(k, v); end -- nothing...
print("Done.")

-- OR

local t = setmetatable({}, {__mode = "kv"});
local k = game.Workspace.Part1;
local v = game.Workspace.Part2;
t[k] = v;

for k, v in next, t do print(k, v); end -- Part1, Part2
wait(1);
k = nil; -- no longer any reference to the key other than in the weak table
-- the key and value still print though b/c garbage has not collected yet
for k, v in next, t do print(k, v); end -- Part1, Part2
wait(1); -- wait for garbage to collect
for k, v in next, t do print(k, v); end -- nothing...
print("Done.")

I think the main thing you need to be wary other than setting variables to nil explicitly is scope. If you create entries in a table using variables that are local in scope they will become nil when you leave that scope. Here's what I mean:

local t = setmetatable({}, {__mode = "k"});

do
    -- new scope
    local k = game.Workspace.Part;
    t[k] = "Value";
end

-- prints eb/c garbage not collected yet
for k, v in next, t do print(k, v); end

wait(3); -- collect garbage

-- nothing prints
for k, v in next, t do print(k, v); end

So when is this useful? I personally have found this most useful for OOP (object oriented programming). We can use weak-tables to store private-values that we don't want the user to mess with in the class.

Here's an example:

local class = {};
local class_mt = {__index = class};
local class_ref = setmetatable({}, {__mode = "k"});

function class.new(x, y)
    local self = {};
    self.x = x;
    self.y = y;
    self = setmetatable(self, class_mt);
    class_ref[self] = {};
    class_ref[self].magnitude = math.sqrt(x*x + y*y);
    return self;
end

function class:getMagnitude()
    return class_ref[self].magnitude;
end

local a = class.new(1, 2, 3);
local b = class.new(-3, 7, 32/4*(-8));

print(a.x, b.y);
print(a:getMagnitude());

-- both entries class_ref[a] and class_ref[b] exist
for k, v in next, class_ref do print(k, v); end

b = nil; 
-- note: b was the only reference to this object outside a weak table

wait(1); -- garbage collection

-- only entry class_ref[a] exists
for k, v in next, class_ref do print(k, v); end 

Of course these "private" values could be accessed as long as the programmer has access to the class_ref table, but if you're writing your class in a module then it's as simple as not returning said table. I use this exact technique to store cframe components in my lua cframe class.

Hope this helped clear some stuff up.

Ad

Answer this question