| 1 | == Proxy Tables == |
---|
| 2 | == Problem to solve == |
---|
| 3 | The problem with Lua tables is that building them isn't an inexpensive operation when done once per frame, or even once per event if it is a large table. When a property or function in Lua calls in to C++ and that function would return a collection of items, proxy tables will forgo the table building unless explicitly told to do so. |
---|
| 4 | |
---|
| 5 | This is one of the more noticeable areas where the Lua implementation varies from Python, and subsequently Javascript.[wiki:documentation/LuaManual/ProxyTables#Why Why?] |
---|
| 6 | |
---|
| 7 | == How == |
---|
| 8 | All proxy tables will override the usual ''!__index'' and/or ''!__newindex'' Lua metamethods. They hook in to the access and setting of tables when the items don't exist directly in the table. At all times, the table of a proxy table will be similar to |
---|
| 9 | {{{ |
---|
| 10 | proxy_table = |
---|
| 11 | { |
---|
| 12 | GetTable = function() call_c_function() end |
---|
| 13 | __index = function() __index_function_in_c() end |
---|
| 14 | __newindex = function() __newindex_function_in_c() end |
---|
| 15 | } |
---|
| 16 | --userdata has a reference to the C++ pointer object to retrieve the data from |
---|
| 17 | userdata:setmetatable(proxy_table) |
---|
| 18 | }}} |
---|
| 19 | It is done all in C++, so that is not exactly how that happens, but it is an accurate enough representation for why the next example would trigger the ''!__index'' and ''!__newindex'' metamethods. |
---|
| 20 | {{{ |
---|
| 21 | --userdata is the same as the previous code block, with proxy_table |
---|
| 22 | --as the metatable |
---|
| 23 | local item = userdata["name"] |
---|
| 24 | --or |
---|
| 25 | local item = userdata.name |
---|
| 26 | --or |
---|
| 27 | local item = userdata[3] |
---|
| 28 | --newindexes |
---|
| 29 | userdata["name"] = "apple" |
---|
| 30 | userdata.name = "orange" |
---|
| 31 | userdtata[2] = "banana" |
---|
| 32 | -- |
---|
| 33 | local item = userdata.name --would still trigger an __index metamethod, but still return 'orange' |
---|
| 34 | }}} |
---|
| 35 | Because ''name'' and ''3'' doesn't exist on the actual table, it triggers the metamethods. The ''!__newindex'' does NOT actually add the item to the table, only adds the item to the C++ object using appropriate get/set methods available. |
---|
| 36 | |
---|
| 37 | == I want the actual table == |
---|
| 38 | Getting the actual table is no problem. Every single proxy table has a method named ''GetTable()''. This will build a table of key,value pairs. Depending on the needs, sometimes the tables are indexed by both integer keys and string keys. In this case, a table value is duplicated and set to both the integer and string indexes. |
---|
| 39 | |
---|
| 40 | Using the ''GetTable()'' function is the only way to to be able to iterate over the table, but beware of the ones that are indexed by both integer keys and string keys. If using pairs(), then iteration will hit each value twice: once for its integer key and once for its string key. To hit each value only once, use ipairs() to iterate only over the integer keys. |
---|
| 41 | |
---|
| 42 | == Why == |
---|
| 43 | The Lua language is fairly simple. It does not have an iterator metamethod like it does for some other operations, and because of this, the ''GetTable()'' method exists for proxy tables. It is a tradeoff of performance for being a little less intuitive. However, accessing individual items is fast and intuitive, because the syntax is the same as if it were an actual value in the table. |
---|
| 44 | |
---|
| 45 | == List of proxy tables == |
---|
| 46 | This is an exhaustive list of functions and properties that return proxy tables. If you think that this is out of date or incorrect, then the file names in the source code will tell you if you are correct. If the file name ends with "Proxy.cpp", then it is proxy table, with the exception of "ElementStyle.cpp". |
---|
| 47 | |
---|
| 48 | {{{ |
---|
| 49 | Context.documents --read only, index by integer and string |
---|
| 50 | Element.attributes --read only, index by string |
---|
| 51 | Element.child_nodes --read only, index by integer |
---|
| 52 | Element.style --read & write, index by string |
---|
| 53 | Event.parameters --read only, index by string |
---|
| 54 | }}} |
---|
| 55 | A function that returns a table that is NOT a proxy table is ''rocket.contexts''. It is read only and indexed by both string and integer. |