Skip to content

0.7 Data representation

Robert Virding edited this page Jan 17, 2024 · 31 revisions

Data representation

Luerl represents data in two ways, an internal and external formats: the external format is designed to interface with native Erlang while the internal format represents data as it is handled inside this implementation of the Lua virtual machine and interpreter.

The luerl library has two groups of functions, those ending in 1 and those that don't. The later don't assume that the arguments are in external format and automatically encodes them, while those ending in 1 assume they are in the internal format.

In most cases using the external format makes code more readable and understandable. However saving the translation costs by directly manipulating data in the internal format can be worth it, once a function for the internal representation is used you are hooked and there is no going back!

To illustrate the following two code examples are identical using the two different formats:

External format

St0 = luerl:init().
F = fun(_, StIn) ->
    {[[{<<"a">>, 1.0}]], StIn}
  end.
St1 = luerl:set_table([t], F, St0).
luerl:eval("return t()", St1).

Internal format

S0 = luerl:init().
F = fun ([], Sti) ->
    {T, Sto} = luerl_emul:alloc_table([{<<"a">>, 1.0}], Sti),
    {[T], Sto}
  end.
S1 = luerl:set_table1([<<"t">>], {erl_func, F}, S0).
luerl:eval("return t()", S1). 

Data types

For the implementation of Lua data types we internally use their corresponding Erlang type:

Lua Erlang
nil atom nil
true/false atoms true/false
strings string binaries
numbers floats
tables #table{} with array for keys 1..n, ttdict for rest
functions #lua_func{} or #erl_mfa{} or #erl_func{}

Nil

Nil is a type represented by the Erlang atom nil, whose main property is to be different from any other value. Lua uses nil as a kind of non-value, to represent the absence of a useful value.

Booleans

Erlang atoms true and false.

Strings

Strings are the same in both formats, Luerl use Erlang binary strings, list strings will be interpreted as a table!

Numbers

Numbers are the same in both internal and external representations, they are simple floats.

Tables

All tables are combinations of Erlang ttdicts and arrays. In each table an array is used for integer keys while an ttdict is used for all other keys. We use this information when building and processing tables.

Tables in Lua are known as associative arrays. All Lua types can be used as keys, except nil.

Tables are the only data structure mechanism in Lua used to implement many data types in simple and efficient ways, lists, sets, arrays, sparse matrices, structures, the kitchen sink, you name it. Tables in Lua are also used for several other purposes like global variables, modules, object and classes, here are some notes about the insides of the Luerl implementation.

In the external format tables are represented as lists of tuples, where the first element is the index and the second the value or as lists of values where the index is implicitly assigned by their position in the list (starting with 1). The tables [1] and [{1,1}] are identical.

In the internal format tables are represented as references, to allocate a table reference the function luerl_heap:alloc_table/2 is that returns a new reference and a state that includes this reference then given a name using luerl:set_table1/3. Single keys can be accessed using luerl:get_table1/2 to resolve a name to a reference and then luerl_emul:get_table_keys/3 to get the value for a given key in the table.

Functions

In the external representations functions are simply functions of the arity/2, where the first argument is a list of function arguments and the state at the time of function execution.

They return a tuple with a list of return values as the first argument and the new state. All parameters are in the external format and all return values need to be in the external format.

In the internal format functions are a tuple with the first element being the atom erl_func and the second a function of the arity/2. It can also be erl_mfa where the second element is an Erlang module name, the third argument is the function name and the fourth data is any useful Erlang data that is passed directly into the function and never modified. The function must also be a function of arity/2. Both return values and function parameters are in the internal format.