29 SWIG and Lua

Lua is an extension programming language designed to support general procedural programming with data description facilities. It also offers good support for object-oriented programming, functional programming, and data-driven programming. Lua is intended to be used as a powerful, light-weight configuration language for any program that needs one. Lua is implemented as a library, written in clean C (that is, in the common subset of ISO C and C++). It's also a really tiny language, less than 6000 lines of code, which compiles to <100 kilobytes of binary code. It can be found at https://www.lua.org

eLua stands for Embedded Lua (can be thought of as a flavor of Lua) and offers the full implementation of the Lua programming language to the embedded world, extending it with specific features for efficient and portable software embedded development. eLua runs on smaller devices like microcontrollers and provides the full features of the regular Lua desktop version. More information on eLua can be found here: http://www.eluaproject.net

29.1 Preliminaries

The current SWIG implementation is designed to work with Lua 5.0.x, 5.1.x and 5.2.x. It should work with later versions of Lua, but certainly not with Lua 4.0 due to substantial API changes. It is possible to either static link or dynamic link a Lua module into the interpreter (normally Lua static links its libraries, as dynamic linking is not available on all platforms). SWIG also has support for eLua starting from eLua 0.8. Due to substantial changes between SWIG 2.x and SWIG 3.0 and unavailability of testing platform, eLua status was downgraded to 'experimental'.

29.2 Running SWIG

Suppose that you defined a SWIG module such as the following:

%module example
%{
#include "example.h"
%}
int gcd(int x, int y);
extern double Foo;

To build a Lua module, run SWIG using the -lua option.

$ swig -lua example.i

If building a C++ extension, add the -c++ option:

$ swig -c++ -lua example.i

This creates a C/C++ source file example_wrap.c or example_wrap.cxx. The generated C source file contains the low-level wrappers that need to be compiled and linked with the rest of your C/C++ application to create an extension module.

The name of the wrapper file is derived from the name of the input file. For example, if the input file is example.i, the name of the wrapper file is example_wrap.c. To change this, you can use the -o option. The wrapped module will export one function "int luaopen_example(lua_State* L)" which must be called to register the module with the Lua interpreter. The name "luaopen_example" depends upon the name of the module.

To build an eLua module, run SWIG using -lua and add either -elua or -eluac.

$ swig -lua -elua example.i

or

$ swig -lua -eluac example.i

The -elua option puts all the C function wrappers and variable get/set wrappers in rotables. It also generates a metatable which will control the access to these variables from eLua. It also offers a significant amount of module size compression. On the other hand, the -eluac option puts all the wrappers in a single rotable. With this option, no matter how huge the module, it will consume no additional microcontroller SRAM (crass compression). There is a catch though: Metatables are not generated with -eluac. To access any value from eLua, one must directly call the wrapper function associated with that value.

29.2.1 Additional command line options

The following table list the additional commandline options available for the Lua module. They can also be seen by using:

swig -lua -help 
Lua specific options
-elua Generates LTR compatible wrappers for smaller devices running elua.
-eluac LTR compatible wrappers in "crass compress" mode for elua.
-nomoduleglobal Do not register the module name as a global variable but return the module table from calls to require.
-no-old-metatable-bindings Disable backward compatibility: old-style binding names generations and a few other things. Explanations are included in appropriate later sections. This option is considered deprecated and will be removed in the near future.
-squash-bases Squashes symbols from all inheritance tree of a given class into itself. Emulates pre-SWIG3.0 inheritance. Insignificantly speeds things up, but increases memory consumption.

29.2.2 Compiling and Linking and Interpreter

Normally Lua is embedded into another program and will be statically linked. An extremely simple stand-alone interpreter (min.c) is given below:

#include <stdio.h>
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"

extern int luaopen_example(lua_State* L); // declare the wrapped module

int main(int argc, char* argv[])
{
 lua_State *L;
 if (argc<2)
 {
  printf("%s: <filename.lua>\n", argv[0]);
  return 0;
 }
 L=lua_open();
 luaopen_base(L);       // load basic libs (eg. print)
 luaopen_example(L);    // load the wrapped module
 if (luaL_loadfile(L, argv[1])==0) // load and run the file
  lua_pcall(L, 0, 0, 0);
 else
  printf("unable to load %s\n", argv[1]);
 lua_close(L);
 return 0;
}

A much improved set of code can be found in the Lua distribution src/lua/lua.c. Include your module, just add the external declaration & add a #define LUA_EXTRALIBS {"example", luaopen_example}, at the relevant place.

The exact commands for compiling and linking vary from platform to platform. Here is a possible set of commands of doing this:

$ swig -lua example.i -o example_wrap.c
$ gcc -I/usr/include/lua -c min.c -o min.o
$ gcc -I/usr/include/lua -c example_wrap.c -o example_wrap.o
$ gcc -c example.c -o example.o
$ gcc -I/usr/include/lua -L/usr/lib/lua min.o example_wrap.o example.o -o my_lua

For eLua, the source must be built along with the wrappers generated by SWIG. Make sure the eLua source files platform_conf.h and auxmods.h are updated with the entries of your new module. Please note: "mod" is the module name.

/* Sample platform_conf.h */
#define LUA_PLATFORM_LIBS_ROM\
  _ROM( AUXLIB_PIO, luaopen_pio, pio_map )\
  _ROM( AUXLIB_TMR, luaopen_tmr, tmr_map )\
  _ROM( AUXLIB_MOD, luaopen_mod, mod_map )\
  ....
/* Sample auxmods.h */
#define AUXLIB_PIO       "pio"
LUALIB_API int ( luaopen_pio )(lua_State *L );

#define AUXLIB_MOD       "mod"
LUALIB_API int ( luaopen_mod )(lua_State *L );
....

More information on building and configuring eLua can be found here: http://www.eluaproject.net/doc/v0.8/en_building.html

29.2.3 Compiling a dynamic module

Most, but not all platforms support the dynamic loading of modules (Windows & Linux do). Refer to the Lua manual to determine if your platform supports it. For compiling a dynamically loaded module the same wrapper can be used. Assuming you have code you need to link to in a file called example.c, the commands will be something like this:

$ swig -lua example.i -o example_wrap.c
$ gcc -fPIC -I/usr/include/lua -c example_wrap.c -o example_wrap.o
$ gcc -fPIC -c example.c -o example.o
$ gcc -shared -I/usr/include/lua -L/usr/lib/lua example_wrap.o example.o -o example.so

The wrappers produced by SWIG can be compiled and linked with Lua 5.1.x and later. The loading is extremely simple.

require("example")

For those using Lua 5.0.x, you will also need an interpreter with the loadlib function (such as the default interpreter compiled with Lua). In order to dynamically load a module you must call the loadlib function with two parameters: the filename of the shared library, and the function exported by SWIG. Calling loadlib should return the function, which you then call to initialise the module

my_init=loadlib("example.so", "luaopen_example") -- for Unix/Linux
--my_init=loadlib("example.dll", "luaopen_example") -- for Windows
assert(my_init) -- make sure it's not nil
my_init()       -- call the init fn of the lib

Or can be done in a single line of Lua code

assert(loadlib("example.so", "luaopen_example"))()

If the code didn't work, don't panic. The best thing to do is to copy the module and your interpreter into a single directory and then execute the interpreter and try to manually load the module (take care, all this code is case sensitive).

a, b, c=package.loadlib("example.so", "luaopen_example") -- for Unix/Linux
--a, b, c=package.loadlib("example.dll", "luaopen_example") -- for Windows
print(a, b, c)

Note: for Lua 5.0:
The loadlib() function is in the global namespace, not in a package. So it's just loadlib().

if 'a' is a function, this is all working fine, all you need to do is call it

  a()

to load your library which will add a table 'example' with all the functions added.

If it doesn't work, look at the error messages, in particular message 'b'
The specified module could not be found.
Means that is cannot find the module, check your the location and spelling of the module.
The specified procedure could not be found.
Means that it loaded the module, but cannot find the named function. Again check the spelling, and if possible check to make sure the functions were exported correctly.
'loadlib' not installed/supported
Is quite obvious (Go back and consult the Lua documents on how to enable loadlib for your platform).

29.2.4 Using your module

Assuming all goes well, you will be able to this:

$ ./my_lua
> print(example.gcd(4, 6))
2
> print(example.Foo)
3
> example.Foo=4
> print(example.Foo)
4
>

29.3 A tour of basic C/C++ wrapping

By default, SWIG tries to build a very natural Lua interface to your C/C++ code. This section briefly covers the essential aspects of this wrapping.

29.3.1 Modules

The SWIG module directive specifies the name of the Lua module. If you specify `module example', then everything is wrapped into a Lua table 'example' containing all the functions and variables. When choosing a module name, make sure you don't use the same name as a built-in Lua command or standard module name.

29.3.2 Functions

Global functions are wrapped as new Lua built-in functions. For example,

%module example
int fact(int n);

creates a built-in function example.fact(n) that works exactly like you think it does:

> print example.fact(4)
24
>

To avoid name collisions, SWIG create a Lua table which keeps all the functions, constants, classes and global variables in. It is possible to copy the functions, constants and classes (but not variables) out of this and into the global environment with the following code. This can easily overwrite existing functions, so this must be used with care.

> for k, v in pairs(example) do _G[k]=v end
> print(fact(4))
24
>

It is also possible to rename the module with an assignment.

> e=example
> print(e.fact(4))
24
> print(example.fact(4))
24

29.3.3 Global variables

Global variables (which are linked to C code) are supported, and appear to be just another variable in Lua. However the actual mechanism is more complex. Given a global variable:

%module example
extern double Foo;

SWIG will effectively generate two functions example.Foo_set() and example.Foo_get(). It then adds a metatable to the table 'example' to call these functions at the correct time (when you attempt to set or get examples.Foo). Therefore if you were to attempt to assign the global to another variable, you will get a local copy within the interpreter, which is no longer linked to the C code.

> print(example.Foo)
3
> c=example.Foo   -- c is a COPY of example.Foo, not the same thing
> example.Foo=4
> print(c)
3
> c=5 -- this will not affect the original example.Foo
> print(example.Foo, c)
4    5

It is therefore not possible to 'move' the global variable into the global namespace as it is with functions. It is however, possible to rename the module with an assignment, to make it more convenient.

> e=example
> -- e and example are the same table
> -- so e.Foo and example.Foo are the same thing
> example.Foo=4
> print(e.Foo)
4

If a variable is marked with the %immutable directive then any attempts to set this variable will cause a Lua error. Given a global variable:

%module example
%immutable;
extern double Foo;
%mutable;

SWIG will allow the reading of Foo but when a set attempt is made, an error function will be called.

> print(e.Foo) -- reading works ok
4
> example.Foo=40 -- but writing does not
This variable is immutable
stack traceback:
        [C]: ?
        [C]: ?
        stdin:1: in main chunk
        [C]: ?

For those people who would rather that SWIG silently ignore the setting of immutables (as previous versions of the Lua bindings did), adding a -DSWIGLUA_IGNORE_SET_IMMUTABLE compile option will remove this.

Unlike earlier versions of the binding, it is now possible to add new functions or variables to the module, just as if it were a normal table. This also allows the user to rename/remove existing functions and constants (but not linked variables, mutable or immutable). Therefore users are recommended to be careful when doing so.

> -- example.PI does not exist
> print(example.PI)
nil
> example.PI=3.142 -- new value added
> print(example.PI)
3.142

If you have used the -eluac option for your eLua module, you will have to follow a different approach while manipulating global variables. (This is not applicable for wrappers generated with -elua)

> -- Applicable only with -eluac. (num is defined)
> print(example.num_get())
20
> example.num_set(50) -- new value added
> print(example.num_get())
50

In general, functions of the form "variable_get()" and "variable_set()" are automatically generated by SWIG for use with -eluac.

29.3.4 Constants and enums

Because Lua doesn't really have the concept of constants, C/C++ constants are not really constant in Lua. They are actually just a copy of the value into the Lua interpreter. Therefore they can be changed just as any other value. For example given some constants:

%module example
%constant int ICONST=42;
#define    SCONST      "Hello World"
enum Days{SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY};

This is 'effectively' converted into the following Lua code:

example.ICONST=42
example.SCONST="Hello World"
example.SUNDAY=0
....

Constants are not guaranteed to remain constant in Lua. The name of the constant could be accidentally reassigned to refer to some other object. Unfortunately, there is no easy way for SWIG to generate code that prevents this. You will just have to be careful.

If you're using eLua and have used -elua or -eluac to generate your wrapper, macro constants and enums should be accessed through a rotable called "const". In eLua, macro constants and enums are guaranteed to remain constants since they are all contained within a rotable. A regular C constant is accessed from eLua just as if it were a regular global variable, just that the property of value immutability is demonstrated if an attempt at modifying a C constant is made.

> print(example.ICONST)
10
> print(example.const.SUNDAY)
0
> print(example.const.SCONST)
Hello World

29.3.4.1 Constants/enums and classes/structures

Enums are exported into a class table. For example, given some enums:

%module example
enum Days { SUNDAY = 0, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY };
struct Test {
  enum { TEST1 = 10, TEST2 = 20 };
#ifdef __cplusplus // There are no static members in C
  static const int ICONST = 12;
#endif
};

There is a slight difference in behaviour wrapping C and C++ code due to the different scoping rules of C and C++. The wrapped C++ code is used as follows from Lua code:

> print(example.SUNDAY)
0
> print(example.Test.TEST1)
10
> print(example.Test.ICONST)
12

Enums within a C struct are in the global namespace and are used as follows from Lua

> print(example.SUNDAY)
0
> -- See the difference here
> print(example.TEST1)
10

Compatibility Note: Versions of SWIG prior to SWIG-3.0.0 did not generate the class table members above. There is no change in the C wrappers, but the following code was the only way to access these constants/enums when wrapping C++ member constants:

> print(example.Test_TEST1)
10
> print(example.Test_ICONST)
12

The old-style bindings are still generated in addition to the new ones. If the -no-old-metatable-bindings option is used, then these old-style bindings are not generated.

It is worth mentioning, that example.Test.TEST1 and example.Test_TEST1 are different entities and changing one does not change the other. Given the fact that these are constants and they are not supposed to be changed, it is up to you to avoid such issues.

29.3.5 Pointers

C/C++ pointers are fully supported by SWIG. Furthermore, SWIG has no problem working with incomplete type information. Given a wrapping of the <file.h> interface:

%module example

FILE *fopen(const char *filename, const char *mode);
int fputs(const char *, FILE *);
int fclose(FILE *);

When wrapped, you will be able to use the functions in a natural way from Lua. For example:

> f=example.fopen("junk", "w")
> example.fputs("Hello World", f)
> example.fclose(f)

Unlike many scripting languages, Lua has had support for pointers to C/C++ object built in for a long time. They are called 'userdata'. Unlike many other SWIG versions which use some kind of encoded character string, all objects will be represented as a userdata. The SWIG-Lua bindings provides a special function swig_type(), which if given a userdata object will return the type of object pointed to as a string (assuming it was a SWIG wrapped object).

> print(f)
userdata: 003FDA80
> print(swig_type(f))
FILE * -- it's a FILE*

Lua enforces the integrity of its userdata, so it is virtually impossible to corrupt the data. But as the user of the pointer, you are responsible for freeing it, or closing any resources associated with it (just as you would in a C program). This does not apply so strictly to classes & structs (see below). One final note: if a function returns a NULL pointer, this is not encoded as a userdata, but as a Lua nil.

> f=example.fopen("not there", "r") -- this will return a NULL in C
> print(f)
nil

29.3.6 Structures

If you wrap a C structure, it is also mapped to a Lua userdata. By adding a metatable to the userdata, this provides a very natural interface. For example,

struct Point{
  int x, y;
};

is used as follows:

> p=example.new_Point()
> p.x=3
> p.y=5
> print(p.x, p.y)
3       5
>

Similar access is provided for unions and the data members of C++ classes.
C structures can be created using a function new_Point(), and both C structures and C++ classes can be created using just the name Point().

If you print out the value of p in the above example, you will see something like this:

> print(p)
userdata: 003FA320

Like the pointer in the previous section, this is held as a userdata. However, additional features have been added to make this more usable. SWIG effectively creates some accessor/mutator functions to get and set the data. These functions will be added to the userdata's metatable. This provides the natural access to the member variables that were shown above (see end of the document for full details).

const members of a structure are read-only. Data members can also be forced to be read-only using the immutable directive. As with other immutables, setting attempts will be cause an error. For example:

struct Foo {
  ...
  %immutable;
  int x;        // Read-only members
  char *name;
  %mutable;
  ...
};

The mechanism for managing char* members as well as array members is similar to other languages. It is somewhat cumbersome and should probably be better handled by defining of typemaps (described later).

When a member of a structure is itself a structure, it is handled as a pointer. For example, suppose you have two structures like this:

struct Foo {
  int a;
};

struct Bar {
  Foo f;
};

Now, suppose that you access the f attribute of Bar like this:

> b = Bar()
> x = b.f

In this case, x is a pointer that points to the Foo that is inside b. This is the same value as generated by this C code:

Bar b;
Foo *x = &b->f;       // Points inside b

Because the pointer points inside the structure, you can modify the contents and everything works just like you would expect. For example:

> b = Bar()
> b.f.a = 3               -- Modify attribute of structure member
> x = b.f
> x.a = 3                 -- Modifies the same structure

For eLua with the -eluac option, structure manipulation has to be performed with specific structure functions generated by SWIG. Let's say you have the following structure definition:

struct data {
  int x, y;
  double z;
};

> --From eLua
> a = example.new_data()
> example.data_x_set(a, 10)
> example.data_y_set(a, 20)
> print(example.data_x_get(a), example.data_y_get(a))
10 20

In general, functions of the form "new_struct()", "struct_member_get()", "struct_member_set()" and "free_struct()" are automatically generated by SWIG for each structure defined in C. (Please note: This doesn't apply for modules generated with the -elua option)

29.3.7 C++ classes

C++ classes are wrapped by a Lua userdata as well. For example, if you have this class,

class List {
public:
  List();
  ~List();
  int  search(char *item);
  void insert(char *item);
  void remove(char *item);
  char *get(int n);
  int  length;
};

you can use it in Lua like this:

> l = example.List()
> l:insert("Ale")
> l:insert("Stout")
> l:insert("Lager")
> print(l:get(1))
Stout
> print(l:length)
3
>

(Note: for calling methods of a class, you use class:method(args), not class.method(args), it's an easy mistake to make. However for data attributes it is class.attribute)

Class data members are accessed in the same manner as C structures. Static class members present a special problem for Lua, as Lua doesn't have support for such features. Therefore, SWIG generates wrappers that try to work around some of these issues. To illustrate, suppose you have a class like this:

class Spam {
public:
  static void foo();
  static int bar;
};

In Lua, C++ static members can be accessed as follows:

> example.Spam.foo()            -- calling Spam::foo()
> a=example.Spam.bar            -- reading Spam::bar 
> example.Spam.bar=b            -- writing to Spam::bar

It is not (currently) possible to access static members of an instance:

> s=example.Spam()              -- s is a Spam instance
> s.foo()                       -- Spam::foo() via an instance
                                -- does NOT work

Compatibility Note: In versions prior to SWIG-3.0.0 only the following names would work:

> example.Spam_foo()            -- calling Spam::foo()
> a=example.Spam_bar            -- reading Spam::bar 
> example.Spam_bar=b            -- writing to Spam::bar

Both style names are generated by default now. However, if the -no-old-metatable-bindings option is used, then the backward compatible names are not generated in addition to ordinary ones.

29.3.8 C++ inheritance

SWIG is fully aware of issues related to C++ inheritance. Therefore, if you have classes like this

class Foo {
...
};

class Bar : public Foo {
...
};

And if you have functions like this

void spam(Foo *f);

then the function spam() accepts a Foo pointer or a pointer to any class derived from Foo.

It is safe to use multiple inheritance with SWIG.

29.3.9 Pointers, references, values, and arrays

In C++, there are many different ways a function might receive and manipulate objects. For example:

void spam1(Foo *x);      // Pass by pointer
void spam2(Foo &x);      // Pass by reference
void spam3(Foo x);       // Pass by value
void spam4(Foo x[]);     // Array of objects

In SWIG, there is no detailed distinction like this--specifically, there are only "objects". There are no pointers, references, arrays, and so forth. Because of this, SWIG unifies all of these types together in the wrapper code. For instance, if you actually had the above functions, it is perfectly legal to do this:

> f = Foo()           -- Create a Foo
> spam1(f)            -- Ok. Pointer
> spam2(f)            -- Ok. Reference
> spam3(f)            -- Ok. Value.
> spam4(f)            -- Ok. Array (1 element)

Similar behaviour occurs for return values. For example, if you had functions like this,

Foo *spam5();
Foo &spam6();
Foo  spam7();

then all three functions will return a pointer to some Foo object. Since the third function (spam7) returns a value, newly allocated memory is used to hold the result and a pointer is returned (Lua will release this memory when the return value is garbage collected). The other two are pointers which are assumed to be managed by the C code and so will not be garbage collected.

29.3.10 C++ overloaded functions

C++ overloaded functions, methods, and constructors are mostly supported by SWIG. For example, if you have two functions like this:

void foo(int);
void foo(char *c);

You can use them in Lua in a straightforward manner:

> foo(3)           -- foo(int)
> foo("Hello")     -- foo(char *c)

However due to Lua's coercion mechanism is can sometimes do strange things.

> foo("3")           -- "3" can be coerced into an int, so it calls foo(int)!

As this coercion mechanism is an integral part of Lua, there is no easy way to get around this other than renaming of functions (see below).

Similarly, if you have a class like this,

class Foo {
public:
  Foo();
  Foo(const Foo &);
  ...
};

you can write Lua code like this:

> f = Foo()          -- Create a Foo
> g = Foo(f)         -- Copy f

Overloading support is not quite as flexible as in C++. Sometimes there are methods that SWIG can't disambiguate. For example:

void spam(int);
void spam(short);

or

void foo(Bar *b);
void foo(Bar &b);

If declarations such as these appear, you will get a warning message like this:

example.i:12: Warning 509: Overloaded method spam(short) effectively ignored,
example.i:11: Warning 509: as it is shadowed by spam(int).

To fix this, you either need to ignore or rename one of the methods. For example:

%rename(spam_short) spam(short);
...
void spam(int);
void spam(short);   // Accessed as spam_short

or

%ignore spam(short);
...
void spam(int);
void spam(short);   // Ignored

SWIG resolves overloaded functions and methods using a disambiguation scheme that ranks and sorts declarations according to a set of type-precedence rules. The order in which declarations appear in the input does not matter except in situations where ambiguity arises--in this case, the first declaration takes precedence.

Please refer to the "SWIG and C++" chapter for more information about overloading.

Dealing with the Lua coercion mechanism, the priority is roughly (integers, floats, strings, userdata). But it is better to rename the functions rather than rely upon the ordering.

29.3.11 C++ operators

Certain C++ overloaded operators can be handled automatically by SWIG. For example, consider a class like this:

class Complex {
private:
  double rpart, ipart;
public:
  Complex(double r = 0, double i = 0) : rpart(r), ipart(i) { }
  Complex(const Complex &c) : rpart(c.rpart), ipart(c.ipart) { }
  Complex &operator=(const Complex &c);
  Complex operator+(const Complex &c) const;
  Complex operator-(const Complex &c) const;
  Complex operator*(const Complex &c) const;
  Complex operator-() const;

  double re() const { return rpart; }
  double im() const { return ipart; }
};

When wrapped, it works like you expect:

> c = Complex(3, 4)
> d = Complex(7, 8)
> e = c + d
> e:re()
10.0
> e:im()
12.0

One restriction with operator overloading support is that SWIG is not able to fully handle operators that aren't defined as part of the class. For example, if you had code like this

class Complex {
...
friend Complex operator+(double, const Complex &c);
...
};

then SWIG doesn't know what to do with the friend function--in fact, it simply ignores it and issues a warning. You can still wrap the operator, but you may have to encapsulate it in a special function. For example:

%rename(Complex_add_dc) operator+(double, const Complex &);
...
Complex operator+(double, const Complex &c);

There are ways to make this operator appear as part of the class using the %extend directive. Keep reading.

Also, be aware that certain operators don't map cleanly to Lua, and some Lua operators don't map cleanly to C++ operators. For instance, overloaded assignment operators don't map to Lua semantics and will be ignored, and C++ doesn't support Lua's concatenation operator (..).

In order to keep maximum compatibility within the different languages in SWIG, the Lua bindings uses the same set of operator names as Python. Although internally it renames the functions to something else (on order to work with Lua).

The current list of operators which can be overloaded (and the alternative function names) are:

Note: in Lua, only the equals, less than, and less than equals operators are defined. The other operators (!=, >, >=) are achieved by using a logical not applied to the results of other operators.

The following operators cannot be overloaded (mainly because they are not supported in Lua)

SWIG also accepts the __str__() member function which converts an object to a string. This function should return a const char*, preferably to static memory. This will be used for the print() and tostring() functions in Lua. Assuming the complex class has a function

const char* __str__() {
  static char buffer[255];
  sprintf(buffer, "Complex(%g, %g)", this->re(), this->im());
  return buffer;
}

Then this will support the following code in Lua

> c = Complex(3, 4)
> d = Complex(7, 8)
> e = c + d
> print(e)
Complex(10, 12)
> s=tostring(e) -- s is the number in string form
> print(s)
Complex(10, 12)

It is also possible to overload the operator[], but currently this cannot be automatically performed. To overload the operator[] you need to provide two functions, __getitem__() and __setitem__()

class Complex {
  //....
  double __getitem__(int i)const; // i is the index, returns the data
  void __setitem__(int i, double d); // i is the index, d is the data
};

C++ operators are mapped to Lua predefined metafunctions. Class inherits from its bases the following list of metafunctions ( thus inheriting the folloging operators and pseudo-operators):

No other lua metafunction is inherited. For example, __gc is not inherited and must be redefined in every class. __tostring is subject to a special handling. If absent in class and in class bases, a default one will be provided by SWIG.

29.3.12 Class extension with %extend

One of the more interesting features of SWIG is that it can extend structures and classes with new methods. In the previous section, the Complex class would have benefited greatly from an __str__() method as well as some repairs to the operator overloading. It can also be used to add additional functions to the class if they are needed.

Take the original Complex class

class Complex {
private:
  double rpart, ipart;
public:
  Complex(double r = 0, double i = 0) : rpart(r), ipart(i) { }
  Complex(const Complex &c) : rpart(c.rpart), ipart(c.ipart) { }
  Complex &operator=(const Complex &c);
  Complex operator+(const Complex &c) const;
  Complex operator-(const Complex &c) const;
  Complex operator*(const Complex &c) const;
  Complex operator-() const;

  double re() const { return rpart; }
  double im() const { return ipart; }
};

Now we extend it with some new code

%extend Complex {
  const char *__str__() {
    static char tmp[1024];
    sprintf(tmp, "Complex(%g, %g)", $self->re(), $self->im());
    return tmp;
  }
  bool operator==(const Complex& c) {
    return ($self->re()==c.re() && $self->im()==c.im());
  }
};

Now, in Lua

> c = Complex(3, 4)
> d = Complex(7, 8)
> e = c + d
> print(e)      -- print uses __str__ to get the string form to print
Complex(10, 12)
> print(e==Complex(10, 12))  -- testing the == operator
true
> print(e!=Complex(12, 12))  -- the != uses the == operator
true

Extend works with both C and C++ code, on classes and structs. It does not modify the underlying object in any way---the extensions only show up in the Lua interface. The only item to take note of is the code has to use the '$self' instead of 'this', and that you cannot access protected/private members of the code (as you are not officially part of the class).

29.3.13 Using %newobject to release memory

If you have a function that allocates memory like this,

char *foo() {
  cha