LuaTable to .net collections

May 4, 2014 at 6:59 PM
Edited May 4, 2014 at 6:59 PM
Hi, I have tried neo lua recently. Its quite easier to use as compared to luainterface. :) . However, I am stuck on how to use data of luatable in host code. for example
// a private static function which accepts luatable
private static void LuaTableFunctor(Neo.IronLua.LuaTable lt)
{
      // I want to read the data here.
}

//host code
dynamic g = luaEnv.CreateEnvironment(); 
g.LuaTableFunctor = new Action<Neo.IronLua.LuaTable>(LuaTableFunctor);

//Lua script
t = {};
t[0] = 2001;
t[1] = 12;
LuaTableFunctor(t);
How to get the data from luatable ?
Currently as a workaround, i am using clr List<> instead. But I need to change all my existing scripts then, which are using lua tables.
May 4, 2014 at 8:46 PM
The LuaTable has a index to access the content.
 private static void TestTable(LuaTable t)
{
  Console.WriteLine("{0}, {1}", t[0], t[1]);
  t[2]="Hallo";
}
Theres is also IEnumerable implementation.

Btw. There is also a dynamic interface, which let csharp access the table like in lua.
private static void Table(dynamic t)
{
  t.hallo = "Hallo";
}
May 5, 2014 at 8:58 AM
Hi,
Thanks for the prompt reply. It works but t.length always returns -1. How to get total number of elements ( something equivalent to getn in lua ) ?
May 5, 2014 at 9:32 AM
-1 means that there is no array order. I will recheck the documentation, may be I misunderstood something.

The reason in your case is, that you started the index with zero. Lua is one-based. That's why you see a -1 in length.
foreach(var c in table)
Should help you.
May 5, 2014 at 10:32 AM
So, I checked the length operator. And I am suprised.

This is code, that I let run under c-lua:
t = {};
t[0] = 1;
t[1] = 2;
print(#t); -- 1 aha lua counts from one
t[2] = 3;
print(#t); -- 2 tree values, but only two are count
t[4] = 3;
print(#t); -- 4  but 3 is mssing?
t[400] = 400;
t[401] = 401;
print(#t); -- still 4, now I am confused?


t2 = {10, 20, nil, 40}
print(#t2); -- 4 but documentations says this is not a sequence?
Can someone explain the rules?

I will change NeoLua, that it returns the highest positve index in length (next version 0.8.11 hopefully sunday). And does not check if it is a sequence. Until someone can explain how lua it does?
May 11, 2014 at 2:24 PM
Edited May 11, 2014 at 2:26 PM
Lua # operator returns the length of the array part of the table. Arrays are indexed from 1, so t[0] is in the hash map part of the table.
Officially Lua tables are just associative arrays and # operators returns the index of the last integer indexed value in the table, where "last" means "followed by nil". Its results are undefined if all the integer keys in the table aren't consecutive.
Lua will preallocate some memory when you index the array, so indexing both 1 and 2 preallocated both slot 3 and 4. It's an heuristic.
t={}
t[1]=1
t[2]=1
t[3]=1
t[4]=1
t[8]=1
print(#t) -- 8
In this example, Lua allocated for 8 elements after 4 were used. Index 9 was not allocated.
t={}
t[1]=1
t[2]=1
t[4]=1
t[8]=1
print(#t) -- 4
With tis example Lua allocated for 4 elements after 2 slots were used. Leaving slot 3 unused stopped allocating for 8 elements.
May 11, 2014 at 4:27 PM
That is not nice, what lua does, because the behavior of the length operator depends on the implementation.
t={}
t[1]=1
t[2]=1
t[4]=1
t[8]=1
t[3]=1
print(#t); -- 4
Is there a need to implement this behavior? Because NeoLua stores members and indices in the same array, so it is hard to find out the length of the index in the way of lua.
May 12, 2014 at 3:54 PM
Note, that the official statement is "Its (#'s) results are undefined if all the integer keys in the table aren't consecutive"!
Therefore, I think it unnecessary to implement this behavior.

I guess, as the case, lua uses array part or hash map part optimization. If key in the table are consecutive lua use array part , otherwise (eg when the array is too small) lua use hash map part optimization.
May 12, 2014 at 9:10 PM
To check, if all integer keys are consecutive, is also very expensive operation.
I thing that is the reason of the behavior of c-lua.

Hopefully nobody is angry about:
t={}
t[1]=1
t[2]=1
t[4]=1
t[8]=1
print(#t); -- NeoLua returns 8
May 13, 2014 at 8:02 AM
Edited May 13, 2014 at 8:06 AM
Why do not you use the count () method?
            LuaTable ltObj = new LuaTable();
            ltObj[1] = 1;
            ltObj[2] = 1;
            ltObj[4] = 1;
            ltObj[8] = 1;
            Console.WriteLine("ltObj.Length: {0}", ltObj.Length);   // -1
            Console.WriteLine("ltObj.Count(): {0}", ltObj.Count()); // 4
Otherwise a study, use of extension method
eg : Use of Enumerable.Count
            object[] aObj = { 1, 1, null, 1, null, null, null, 1 };
            Console.WriteLine("aObj.Count: {0}", aObj.Count(s => s != null));   // 4
May 13, 2014 at 10:46 AM
Edited May 13, 2014 at 10:47 AM
First code:
  • Length: Do you use the latest version? There should be a 8.
  • Count: You are using the Count extension method. This extension counts the return values of the IEnumerable (the key value pairs), not the integer keys.
Second code:
  • The count operator in your case returns the number of values in your array, not the length . The length is 8 not 4.
The behavior of the current version of the LuaTable is changed, it now returns the highest integer key. That is close to the lua behavior. It only differs in extrem cases e.g. t[1] = 1; t[200] = 1; (c-lua = 1, neolua = 200)
May 14, 2014 at 7:35 AM
Jun 1, 2014 at 9:13 PM
I changed it in the version 0.8.13.0.

So, it should work like in the Lua-Documentation.
Jun 2, 2014 at 7:27 AM
Great Job ;) Thanks
Jun 2, 2014 at 4:51 PM
If there are performance issues let me know.