For me, the table is extremely powerful. I like it that it can be used as a sparse array, a hash, a vector, whatever. Of course one must know, at heart, the difference between pairs() and ipairs() and what it means for your data, though ..
So, as someone only very peripherally familiar with Lua, can someone please explain the table thing to me? I've heard Lua fans gush that Lua is tables all the way down, except it seems like there's these tables on the one hand that work like arrays, and those other tables on the other hand that work like objects, and you can't mix them up...
Is that not just an ordinary dynamically typed language with arrays and objects then, except it overloads the word "table" to refer to both?
I'm sure I'm missing something, happy to hear what that is.
So a table is a hashtable. Just about anything can be a key to the hash - a number, a string, a boolean, another table, a userdata. I can't recall if functions and coroutines can be keys but I suspect they could. I definitely know that nil can't be an index.
In Lua - all iterators are implemented as a function + state + current key. When you write "for x in (whatever)", that (whatever) is really a function call like func(state,key). Lua calls it repeatedly to traverse the loop.
Lua will take the first returned value and use it as the new key in the next call to func(). Once the function returns nil as the first value (or just returns no values) - the loop stops.
There are two functions - pairs and ipairs - that really just return the built-in next function with a starting key. pairs returns (lua's next(), the table, nil), and ipairs returns (next(), the table, 0).
(there's a bit more to it than that and some under-the-hood changes between Lua versions but we'll just go with that explanation).
Lua repeatedly calls that next() function with the table and previous key.
Say you had an array like table like { [1] = some_value, [2] = another_value }.
When you write something like "for i,v in ipairs(a_table)" that roughly expands to:
* pairs() returns next(), the table, 0.
* Lua calls next(table, 0) and next returns (1, some_value)
* Lua calls next(table, 1) and next returns (2, another_value)
* Lua calls next(table, 2) and next returns nil.
So - when is a table an array?When you can iterate through it with sequential, integer keys.
Note - you don't necessarily need to use ipairs to iterate. Lua also has a numerical "for" loop so you could do that. Or - if you want to start your arrays at 0 instead of one you can write your own ipairs() like function in just a few lines of code. Observe:
local zpair_it = function(table, key)
key = key + 1
if table[key] then
return key, table[key]
end
end
local zpairs = function(table)
return zpair_it, table, -1
end
local tab = { [0] = 'yay', [1] = 'huzzah' }
for i,v in zpairs(tab) do
print(i,v)
end
There - now instead of using ipairs(), you can use zpairs() with zero-based indexes.As far as using like objects, that's getting into metatables and stuff but - basically lua has a syntactical sugar to make object-orientation nice.
If you write "obj:func()" - that's the same as writing "obj.func(obj)" - assuming "obj" is a table, Lua will fetch the "func" key from the table, then call it as a function with "obj" as the first argument (this can be referred to as self within your function definition).
If Lua tries to fetch "func" from your table and it doesn't exist - it will check to see if your table has a metatable defined with an __index metamethod (or table) and pull func from that. So - your table could just have your object's actual state data on it, and functions are referenced in a separate metatable.
Observe:
local dog_methods = {
bark = function(self)
print("bark bark I'm a",self.breed)
end
}
local dog_metatable = {
__index = dog_methods
}
local huskie = setmetatable({
breed = 'huskie'
}, dog_metatable)
local collie = setmetatable({
breed = 'collie'
}, dog_metatable)
huskie:bark()
collie:bark()
huskie:bark() is equivlanet to huskie.bark(huskie). bark doesn't actually exist on huskie, but huskie has a metatable with an __index table where bark is defined. So the function call is really more like dog_methods.bark(huskie).Anyways wow that was a lot. Highly recommend going through the Lua manual. It's not a long read.
Yes, there is:
local l = {[0] = 'a', [1] = 'b', [2] = 'c'}
for i, c in ipairs(l) do
print(i, c)
end
This will only print the last two pairs. Lua is 1-indexed, end of story. You can store values at index zero, but it's no different than storing values at index -1 or index 'lolrofl'. It does not exist in the array-part of the table as far as Lua is concerned. local l = {[0] = 'a', [1] = 'b', [2] = 'c'}
for i = 0,#l do
print(l[i])
end
.. prints:
a
b
c
Lua haters usually don't get past their misunderstanding of tables, but its really quite unfair on the language and those who have used it quite well to do big things ..Either way, I think it's a nitpick to complain about. I've written a decent amount of Lua and there's only been a handful of times where 1-indexing was even relevant to me.
You don't change something like that because it eventually got picked up by game programmers (never the intent of Lua, something that just happened after it was used by the Grim Fandango team, then it took off in the gaming world).