Yes, that's true. It does have drawbacks, but overall I think it is better than say, JavaScript. In JavaScript, a key can be not present in an object, be undefined, be null, be set to some other value, or be present in the prototype. The difference between these can cause very subtle bugs.
//Let's define some object
var obj = {a: true, b: true, c: true, d: true, hasOwnProperty: true}
//Now let's make them falsy in different ways
obj.a = undefined; //set to undefined
obj.b = null; //set to null
obj.c = false; //set to false
delete obj.d; //delete key
delete obj.hasOwnProperty //delete key, but present in prototype
console.log(obj.a) //--> undefined
console.log(obj.b) //--> null
console.log(obj.c) //--> false
console.log(obj.d) //--> undefined
console.log(obj.hasOwnProperty) //--> [Function]
console.log('a' in obj) //--> true
console.log('b' in obj) //--> true
console.log('c' in obj) //--> true
console.log('d' in obj) //--> false
console.log('hasOwnProperty' in obj) //--> true
console.log(obj.a == null) //--> true
console.log(obj.b == null) //--> true
console.log(obj.c == null) //--> false
console.log(obj.d == null) //--> true
console.log(obj.hasOwnProperty == null) //--> false
for(var key in obj) {
console.log(key) //--> prints a, b, c
}
In Lua, the only data structure is a hashtable, which maps any non-nil value to any other non-nil value. It can also be set in the objects __index metamethod/table
local tab = {a = true, b = true, c = true}
-- by default there are none, but we can defined a fallback metatable similar to a prototype method like js's obj.prototype.hasOwnProperty
setmetatable(tab, {__index={c='meta c', d='meta d'}})
-- if it is important that a key is explicitly set to false, do so, otherwise simply remove it
tab.a = false --set to false
tab.b = nil --set to nil
tab.c = nil --set to nil, present in fallback table
tab.d = false --set to false, present in fallback table
print(tab.a) --false
print(tab.b) --nil
print(tab.c) --meta c
print(tab.d) --false
The rules for Lua are simple: Look for the key in the table, if it's not there, check the fallback defined in the metatable, if not, then return nil.
This is especially important in Lua, because any value can be a key, you would have to be sure to delete the key otherwise it could not be garbage collected.
local tab1 = {1,2,3,4,5}
local tab2 = {}
tab2[tab1] = true
for k,v in pairs(tab2) do
tab[k] = nil
end
If this worked like JavaScript, then tab2[tab1] would return nil, but tab1 could not be garbage collected until tab2 is. Because JavaScript objects can only have strings for keys, this is less of an issue.