tags:

views:

735

answers:

3

I'm trying to write some c++ classes for interfacing with LUA and I am confused about the following:

In the following example: Wherigo.ZCommand returns a "Command" objects, also zcharacterFisherman.Commands is an array of Command objects:

With the following LUA code, I understand it and it works by properly (luaL_getn returns 3 in the zcharacterFisherman.Commands c++ set newindex function):

zcharacterFisherman.Commands = {
  Wherigo.ZCommand{a="Talk", b=false, d=true, c="Nothing available"},
  Wherigo.ZCommand{a="Talk", b=false, d=true, c="Nothing available"},
  Wherigo.ZCommand{a="Talk", b=false, d=true, c="Nothing available"},
}

But when the array is defined with the following LUA code with a slightly different syntax luaL_getn returns 0.

zcharacterFisherman.Commands = {
  Talk = Wherigo.ZCommand{a="Talk", b=false, d=true, c="Nothing available"},
  Talk2 = Wherigo.ZCommand{a="Talk", b=false, d=true, c="Nothing available"},
  Talk3 = Wherigo.ZCommand{a="Talk", b=false, d=true, c="Nothing available"},
}

All objects are defined in c++ and the c++ objects hold all the object members so I am trying to just connect LUA to those c++ objects. Is this enough or do I need to post some of my code??

+2  A: 

luaL_getn is for getting the highest numeric element of an array in Lua. An array is a table with only integer indices. When you define a table in Lua (the first example) without explicitly setting indices, you will get an array with elements 1, 2, and 3. Naturally, luaL_getn returns a 3 here. luaL_getn is NOT defined to return the number of elements in the table, it is defined to return the highest numeric index in the table (see http://www.lua.org/manual/5.1/manual.html#pdf-table.maxn)

The second example is NOT using numeric indices, and this table is not a Lua array -- it is more like a hash table. Since luaL_getn only works on true arrays, you wouldn't expect it to work here.

Unfortunately, there is no simple way to get the number of elements in a table (lua_objlen solves a related problem, but does not fix this one). The only way to do it is to either:

  1. Always use array notation. Don't ever use anything else as the keys in your table. You will get a lot of speed-ups this way.
  2. Iterate through your table and count the number of elements when you wish to know the table's size. The language does not provide a one-line method for getting the size of a full table, since general tables are implemented using hashes and do not track their element count.
AHelps
+1  A: 

Lua tables combine both hashtables and standard arrays.

Your first example is equivalent to:

zcharacterFisherman.Commands = {
  [1] = Wherigo.ZCommand{a="Talk", b=false, d=true, c="Nothing available"},
  [2] = Wherigo.ZCommand{a="Talk", b=false, d=true, c="Nothing available"},
  [3] = Wherigo.ZCommand{a="Talk", b=false, d=true, c="Nothing available"},
}

getn helps you to find an empty numeric entry. If t[1]==nil then it is likely that table.getn(t) == 0. In your second example, you do not assign zcharacterFisherman.Commands[1], which is why you are getting 0.

zcharacterFisherman.Commands = {
  [1] = Wherigo.ZCommand{a="Talk", b=false, d=true, c="Nothing available"},
  [2] = Wherigo.ZCommand{a="Talk", b=false, d=true, c="Nothing available"},
  [3] = Wherigo.ZCommand{a="Talk", b=false, d=true, c="Nothing available"},
}
zcharacterFisherman.Commands[1]=nil
print(table.getn(zcharacterFisherman.Commands))

This code will print 0 (or possibly a number >=3)

In general, there is no way to directly get the number of elements in the hashtable portion of the table without iterating over them (e.g. with pairs() )

Dolphin
+2  A: 

Lua is correct.

Your first example is forming a table that contains exactly three entries with indices 1, 2, and 3, none of which are specified explicitly. In this case table.maxn(), the # operator, and lua_objlen() all agree that there are three array elements.

Your second example is forming a table that contains exactly three entries with indices "Talk", "Talk2", and "Talk3", all specified explicitly but none are integers. In this case, table.maxn(), the # operator, and lua_objlen() all agree that there are zero array elements.

Why is this the right answer?

A Lua table is an associative array that can map values of any type (except nil) to values of any type (again, except nil). There is no other general container type in Lua, so tables are used for essentially everything. The implementation is not part of the Lua specification, but in practice a table is indexed as a hash table, and there is no natural ordering of the keys.

However, a common use case for tables is as a container that acts like a conventional array. Such a container has contiguous integer indices, and can be iterated in order. The table implementation makes this particularly efficient for integer keys starting at 1. These entries in the table are physically allocated as a contiguous array, and the keys are neither hashed nor stored. This saves storage space both in allocation overhead and by not storing some of the keys at all. It also saves run time since access is by direct calculation rather than by computing a hash and verifying the matching value.

Since arrays are just tables, the table initializer syntax has been designed to make that case easy and clear, as well as to support the other common use case where keys are strings that happen to be valid identifiers.

Lua 5.1 vs. Lua 5.0

In the current release of Lua (5.1.4, but this is true of all 5.1 releases) the Lua 5.0 functions table.getn(), table.setn(), luaL_getn(), and luaL_setn() are all deprecated, as is the common usage of a table field n for an array to indicate its array length. The table.getn() function is replaced by the # operator, and luaL_getn() by lua_objlen(). There is no equivalent to the setn() functions since Lua now manages the array size behind the scenes.

The # operator is defined on a table to return an integer such that indexing the table by the next larger integer returns nil. For an empty array (e.g. a = {}), it returns 0 because a[1] == nil. For a normal array, it returns the largest index in use. However, if an array has holes (missing elements) then it can return the index preceding any hole or the last index in use. If the actual largest integer index in use is required, the new function table.maxn() can be used, but it has to iterate over all table entries to find that maximum value and thus should only be used when using # can't.

This leads to a now common idiom for adding elements to an array: a[#a+1] = "some new value". This idiom is now often recommended in place of table.insert() for extending tables.

RBerteig
a[#a+1] is also going to be more efficient (and more legible imo) than table.insert. a[#a+1] is just 3 lua instructions, whereas table.insert does more work than that just to make the function call (which does more or less what a[#a+1] does).table.insert is still necessary if you can't add an item at the end of the table.
Dolphin