Writing Swift wrappers for C libraries

Where I talk about my first experience in writing Swift code.


I’ve been kind of bashing Swift recently because of the current buggy state of the tools (SourceKit service and Swift compiler crashes are the most notable offenders). However, I have to admit that Swift has become much more usable as a language than it was the last time I’ve touched it. I still encounter weird seemingly unrelated compilation error messages but (thanks to Stack Overflow and all the people who already encountered something similar) I usually can decipher the errors and either fix them or mourn for things that cannot be fixed.

Swift interaction with C code was a pleasant surprise for me. I’ve decided to practice Swift a bit by creating a wrapper/bindings library for Squirrel language. Squirrel is written in C++ but has C API so it should be simple to import it and use in Swift code. I’ve never actually thought it would be that easy.

Project structure

I’ve decided to create a Swift framework for Squirrel, so a Cocoa Touch Framework template was an obvious choice for me. Squirrel is hosted on SourceForge while my project lives on GitHub, so to simplify things a bit, I’ve added Squirrel sources directly into my project (it seems that Squirrel license permits this kind of thing).

Xcode does display a bunch of compiler warnings when trying to build Squirrel, so I’ve decided to put all the vendor code in a separate framework named CSquirrel while my SwiftSquirrel framework would import it as a dependency. That way I could completely disable compiler warnings generated by the original Squirrel source1.

Working with Squirrel API

As I’ve already mentioned, Squirrel provides C API, which allows working with it from Swift. Somewhat surprisingly for me, most of the things are imported really well. Squirrel VM stack operations can be easily performed with just a little bit of typecasting involved:

func push(value: Int) {
  sq_pushinteger(vm, SQInteger(value))
}

func push(value: Float) {
  sq_pushfloat(vm, SQFloat(value))
}

// ... etc.

Well, there are some quirks to it obviously. For example SQBool is actually an SQUnsignedInteger, which differs from the type of the SQTrue and SQFalse constants (which happens to be Int32 in Swift). The boolean handling gets a bit clunky as the result (since you have to explicitly cast Squirrel boolean constants to SQBool):

func push(value: Bool) {
  sq_pushbool(vm, (value == true) ? SQBool(SQTrue) : SQBool(SQFalse))
}

On the other side, I thought strings would be a pain, but they are handled pretty simple:

func push(value: String) {
  let cString = (value as NSString).UTF8String
  let length = strlen(cString)
  sq_pushstring(vm, cString, SQInteger(length))
}

SQValue

Trying to think like a Swift programmer would, I’ve been using the rich Swift enum facility for all Squirrel types. Squirrel VM interaction is stack-based, so I’ve built the wrapper in such a way that essentially anything that could be pushed into the Squirrel VM stack is described as one of the SQValue enum values2.

SwiftSquirrel is obviously a very early work in progress currently, so the SQValue definition is not yet near to completion, but it looks kind of like that:

public enum SQValue {
    public typealias IntType = Swift.Int
    public typealias FloatType = Swift.Double
    public typealias BoolType = Swift.Bool
    public typealias StringType = Swift.String

    case Int(IntType)
    case Float(FloatType)
    case Bool(BoolType)
    case String(StringType)
    case Object(SQObject)
    case Null
}

Notice that the types of the associated values have to be explicitly namespaced since the enum values have the same names.

There is another thing I’d like to mention since I’ve had some trouble finding a way to implement it. Notice that the FloatType alias of the enum is really a Double? That is intentional. I’ve started with Float and got stuck on the following problem:

I wanted SQValue objects to behave as much as their native Swift counterparts as possible. So arithmetical operations with SQValues should yield appropriate results; pushing Swift values (like usual Ints, Floats etc.) to the Squirrel VM stack should result in pushing the corresponding SQValues, etc., etc.

One could argue that this kind of goes against the Swift philosophy of having strict type information everywhere: the SQValue is a variant type and var x: SQValue could hold anything from Strings to Bools to Floats etc. This is true probably, but I wanted to do play around with operators and literal convertible protocols, so I still did that.

In order to allow assigning Float constants to the SQValue vars, we have to conform to FloatLiteralConvertible:

extension SQValue: FloatLiteralConvertible {
    public init(floatLiteral value: Float) {
        self = .Float(value)
    }
}

Implementation of this protocol is pretty much straightforward. I also had several push overloads in the VMStack protocol:

func push(x: SQValue)
func push(x: Float)

I’ve started writing some unit tests for the Squirrel VM stack wrapper, and then it backfired:

squirrel.stack.push(2.0) // Error! Ambiguous use of 'push'

Of course, it cannot decide which version of push to call!

Thinking about it now, I see that this is my fault of not knowing the language that well. The docs clearly say that

if you do not specify a type for a floating-point literal, Swift infers that you want to create a Double

So what do we have here exactly? Literal 2.0 was inferred to be a Double which then had to be converted to either SQValue or to a Float to be able to be pushed into the Squirrel VM stack. In this case, Swift cannot decide which overload to use and generates the error. The solution I’ve decided to roll with is simple: use Double as the SQValue backing floating point type. Then push functions would look like that:

func push(x: SQValue)
func push(x: Double)

Calling the func with the 2.0 parameter would not be ambiguous anymore since there would be two alternatives: either convert the Double parameter to SQValue or use Double directly without any conversion. Swift uses the latter in this case.

Convert all the types!

List of the push function overloads began to grow3:

func push(x: SQValue)
func push(x: Int)
func push(x: Double)
func push(x: String)
func push(x: Bool)
func push(x: SQObject)
func push(x: SQTable)

I’ve also added a << operator as a more concise form of stack pushing. This operator also required all the overloads to be implemented separately.

The further I went into this rabbit hole the less I liked it. If I needed to add one more type to the mix, I would have to add the corresponding push overload to VMStack protocol, add the implementation and add the << operator overload which calls push.

The push function declarations are almost the same and differ only by the parameter type. Do I really need all of these overloads? Internally all push implementations call the SQValue push implementation, which contained a big switch and called the appropriate Squirrel API func:

func sq_pushstring(v: HSQUIRRELVM, s: UnsafePointer<SQChar>, len: SQInteger)
func sq_pushfloat(v: HSQUIRRELVM, f: SQFloat)
func sq_pushinteger(v: HSQUIRRELVM, n: SQInteger)
func sq_pushbool(v: HSQUIRRELVM, b: SQBool)

Generics you say? I do not really see how they would help. I have some experience with Squirrel C++ bindings, and C++ templates could’ve proven useful here (make the template dependent on the push argument parameter and provide specializations for all required types), but this kind of stuff is not available for Swift generics. It turns out it is not needed either.

Meet SQValueConvertible:

public protocol SQValueConvertible {
    var asSQValue: SQValue { get }
}

Now all that we have to do is provide one push(x: SQValueConvertible) implementation and add the following extension to all the types we want to work with:

extension Int: SQValueConvertible {
    public var asSQValue: SQValue {
        get {
            return SQValue.Int(self)
        }
}

// Provide the similar implementation for Double,
// String, Bool, SQObject, SQTable etc.

Even SQValue itself should conform:

extension SQValue: SQValueConvertible {
    public var asSQValue: SQValue {
        get {
            return self
        }
    }
}

Now calling push(10), push(3.14), push("Hello, World!") would all automatically work and adding one more type is as easy as adding one more extension which implements SQValueConvertible.

Swift baby steps. I am so proud of myself.

Not the last one

I’ve really enjoyed solving this particular problem. It is completely different from what I usually do while writing Objective-C code. I’ve been coding the SwiftSquirrel project at nighttime for the whole last week. That did not go well with getting up and going to work the next days, but it was a lot of fun.

I’ve already had a couple more problems to scratch my head over, but I’ll probably talk about them some other time.

Followup posts


  1. Well, it would probably be better just to fix them, but it is not my goal currently. I just want to practice some Swift. 

  2. SQValue enum values are derived from the Squirrel’s SQObjectType enum with a reasonable addition that Swift enum can also contain the actual value besides representing its type. 

  3. I’ll probably talk about SQObjects more at some other time, for now just take into account that they were there and added more overloads to implement. 


Project maintained by wanderwaltz Hosted on GitHub Pages — Based on theme by mattgraham