lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]

Hi all. I've been working on a Swift interface for Lua. This would be
an alternative to using Lua's C API when you're working with Swift.

A brief overview of Swift for the uninitiated: is a programming
language that compiles directly to native code, interfaces cleanly
with C, has high-level features such as generics, protocols (i.e.
interfaces), type inference, enhanced structs and enums (i.e. can have
methods, be extended, conform to protocols), functional programming
patterns (e.g. map, filter), multiple return values, and more. And
it's only available on Apple platforms, for those who this matters to
(I'm fine with it).

So, to give a brief demonstration of my API in action, here is Listing
28.2 in Roberto's book Programming in Lua, originally in C, translated
to Swift:

    let L = Lua.VirtualMachine()

    let stringxLib = L.createTable()

    stringxLib["split"] = L.createFunction { args in
        if let e = L.checkTypes(args, [.String, .String]) { return .Error(e) }

        let subject = args[0] as String
        let separator = args[1] as String

        let results = L.createTable()
        let fragments = subject.componentsSeparatedByString(separator)
        for (i, fragment) in enumerate(fragments) {
            results[i+1] = fragment
        return .Value(results)

    L.globalTable["stringx"] = stringxLib

This small example demonstrates a few noteworthy concepts:

1. The stack is completely hidden from the user. All operations can be
performed directly on plain Swift objects representing Lua objects.
The Lua object lives as long as the variable is in use (kept track of
via ARC).

2. Arguments and return values to Lua functions written in Swift are
given as plain Swift objects. Such functions can return .Nothing,
.Value(v), or .Values([a, b, c]), or .Error(str), which makes use of
Swift's enums with associated values.

3. Errors are returned from the function since Swift has no exceptions
(yet) and longjmp messes with the stack and needs to be done with
great care. This allows me to isolate it to one function which can
clean up the stack as best as possible.

4. The function created for "split" is a Swift closure and thus
doesn't need to have the Lua state (vm) passed in as an argument since
it closes over it.

5. The registry and global tables are both treated as plain Lua tables
within a Swift wrapper class (called Table), which allows them to be
treated more conveniently, e.g. they use subscript notation to get/set

There are more things this API can do not shown here, especially
offering a convenient API for creating new library types, but I
thought it best to only show a short example for now.

This API is not yet stable or ready for public consumption. I would
love whatever feedback anyone has to offer about this, and I'd be glad
to answer any questions about its implementation.