upvote
It's not really tables all the way down - Lua has datatypes like nil, boolean, number, string, table, userdata + lightuserdata, functions, coroutines. I think that's the entire list, actually.

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.

reply
Tables are kinda-sorta hashes that can hold anything, not unlike JavaScript objects. The array use case is just a table with automatically assigned numeric keys.
reply