Lua C Metatables

  1. Lua C Metatables De
  2. Lua C Injector

These videos describe how to embed Lua into a native application and interface with the Lua C API. They do not cover how to use the scripting language itself. However, I still have an issue with setting the metatables on the file function after loading. Each plugin object has several banks, and when I load them in, I'm getting an extra bank sub-table. It is either a duplicate of one of the tables (not always the same) and sometimes an malformed table that doesn't implement the tostring method.

Lua C Metatables

This first edition was written for Lua 5.0. While still largely relevant for later versions, there are some differences.
The fourth edition targets Lua 5.3 and is available at Amazon and other bookstores.
By buying the book, you also help to support the Lua project.

Programming in Lua
Part IV. The C APIChapter 28. User-Defined Types in C

28.2 – Metatables

Our current implementation has a major security hole.Suppose the user writes something like array.set(io.stdin, 1, 0).The value in io.stdin is a userdatumwith a pointer to a stream (FILE*).Because it is a userdatum,array.set will gladly accept it as a valid argument;the probable result will be a memory corruption(with luck you can get an index-out-of-range error instead).Such behavior is unacceptable for any Lua library.No matter how you use a C library,it should not corrupt C data or produce a core dump from Lua.

To distinguish arrays from other userdata,we create a unique metatable for it.(Remember that userdata can also have metatables.)Then, every time we create an array,we mark it with this metatable;and every time we get an array,we check whether it has the right metatable.Because Lua code cannot change the metatable of a userdatum,it cannot fake our code.

We also need a place to store this new metatable,so that we can access it to create new arrays andto check whether a given userdatum is an array.As we saw earlier,there are two common options for storing the metatable:in the registry,or as an upvalue for the functions in the library.It is customary, in Lua,to register any new C type into the registry,using a type name as the index and the metatable as the value.As with any other registry index,we must choose a type name with care, to avoid clashes.We will call this new type 'LuaBook.array'.

As usual, the auxiliary library offers some functions to help us here.The new auxiliary functions we will use areThe luaL_newmetatable functioncreates a new table (to be used as a metatable),leaves the new table in the top of the stack,and associates the table and the given name in the registry.It does a dual association:It uses the name as a key to the tableand the table as a key to the name.(This dual association allows faster implementations forthe other two functions.)The luaL_getmetatable function retrievesthe metatable associated with tname from the registry.Finally, luaL_checkudata checks whether the object at thegiven stack position is a userdatum with a metatable that matchesthe given name.It returns NULL if the object does not have the correct metatable(or if it is not a userdata);otherwise, it returns the userdata address.

Now we can start our implementation.The first step it to change the function that opens the library.The new version must create a table to be used as the metatable for arrays:

The next step is to change newarray so that it setsthis metatable in all arrays that it creates:The lua_setmetatable function pops a table from the stackand sets it as the metatable of the object at the given index.In our case, this object is the new userdatum.

Finally, setarray, getarray, and getsize have to checkwhether they got a valid array as their first argument.Because we want to raise an error in case of wrong arguments,we define the following auxiliary function:Using checkarray,the new definition for getsize is straightforward:

Because setarray and getarray also share code to check theindex as their second argument,we factor out their common parts in the following function:After the definition of getelem,setarray and getarray are straightforward:Now, if you try something like array.get(io.stdin, 10),you will get a proper error message:

Copyright © 2003–2004 Roberto Ierusalimschy. All rights reserved.

Syntax

  • [[local] mt = ]getmetatable(t) --> retrieve associated metatable for 't'
  • [[local] t = ]setmetatable(t, mt) --> set the metatable for 't' to 'mt' and returns 't'

Parameters

ParameterDetails
tVariable referring to a lua table; can also be a table literal.
mtTable to use as a metatable; can have zero or more metamethod fields set.

Remarks

There are some metamethods not mentioned here. For the full list and their usage, see the corresponding entry in the lua manual.

Creation and usage of metatables

A metatable defines a set of operations which alter the behaviour of a lua object. A metatable is just an ordinary table, which is used in a special way.

Using tables as metamethods

Some metamethods don't have to be functions. To most important example for this is the __index metamethod. It can also be a table, which is then used as lookup. This is quite commonly used in the creation of classes in lua. Here, a table (often the metatable itself) is used to hold all the operations (methods) of the class:

Garbage collector - the __gc metamethod

5.2

Objects in lua are garbage collected. Sometimes, you need to free some resource, want to print a message or do something else when an object is destroyed (collected). For this, you can use the __gc metamethod, which gets called with the object as argument when the object is destroyed. You could see this metamethod as a sort of destructor.

This example shows the __gc metamethod in action. When the inner table assigned to t gets garbage collected, it prints a message prior to being collected. Likewise for the outer table when reaching the end of script:

More metamethods

There are many more metamethods, some of them are arithmetic (e.g. addition, subtraction, multiplication), there are bitwise operations (and, or, xor, shift), comparison (<, >) and also basic type operations like and # (equality and length). Lets build a class which supports many of these operations: a call for rational arithmetic. While this is very basic, it shows the idea.

Make tables callable

There is a metamethod called __call, which defines the bevahiour of the object upon being used as a function, e.g. object(). This can be used to create function objects:

The metamethod is called with the corresponding object, all remaining arguments are passed to the function after that:

Indexing of tables

Lua C Metatables De

Perhaps the most important use of metatables is the possibility to change the indexing of tables. For this, there are two actions to consider: reading the content and writing the content of the table. Note that both actions are only triggered if the corresponding key is not present in the table.

Reading

This could be used to raising an error while reading a non-existent key:

Writing

You may now ask yourself how the actual value is written in the table. In this case, it isn't. The problem here is that metamethods can trigger metamethods, which would result in an infinitive loop, or more precisely, a stack overflow. So how can we solve this? The solution for this is called raw table access.

Raw table access

Sometimes, you don't want to trigger metamethods, but really write or read exactly the given key, without some clever functions wrapped around the access. For this, lua provides you with raw table access methods:

With this, we can now rewrite ower former __newindex method to actually write the value to the table:

Simulating OOP

Instance methods can be written by passing the object as the first argument.

There is some syntactic sugar for this.

We can also add default fields to a class.

Lua C Injector