Gogoa – Cocoa bindings for Go

As usual, some time has passed since my last entry here.

Anyway, I just wanted to share my 2 cents about what has been a nice discovery for me in the last 2 hours.

I don’t actually know why but I was wondering how easy it is to invoke Cocoa from Go. Well [SPOILER] looks like it’s super easy!

The first comfortable piece I encountered, actually, was Go 1.3 changelog where it states:

Finally, the go command now supports packages that import Objective-C files (suffixed .m) through cgo.

 

Since I’m now with Go 1.4.2 I thought: “This should be even easier now!”

Reading through the cgo reference looks like interoperability is getting stronger with Go, despite this comment on SO.

Hahaha… Go’s biggest weakpoint… interoperability. –  Matt JoinerJun 12 ’11 at 13:54

Gimme the code

I know, too much words and no code so far.

Turns out that showing a Cocoa window with Go may be as easy as the following:

If you think this is too clean to be true you are kind of right. I actually started this project on GitHub which performs all the ugly bits underneath. I’d really love you to help me get this a little further.

How does it work?

There’s this go tool called cgo which does most of the magic by itself when you build a hybrid project like this.

The reference is rather comprehensive but I’d like to highlight a few issues I encountered while wrapping the code up.

1. Keep import “C” after the C statements

Let’s take my application.go as an example:

As you can see import "C" is preceded by three directives as per the cgo standard. Make sure the import "C" directive is right after the actual C directives otherwise your code won’t build. This is because C is a pseudo package generated also using the code you provide through those preceding directives.

2. Always specify the compiler directives

Every file exposing the ObjectiveC bindings should specify the following flags at least.

Otherwise you would end up in a long long list of compilation errors. At least this is what happened to me.

3. Always void*

If you end up working with pointers to ObjectiveC classes always convert them into void* before returning them back to Go. If you don’t, passing them back to C/ObjectiveC might become painful or you may end up with errors like the following:

struct size calculation error off=8 bytesize=0

At least this is what occurred to me. You may help me see the light with this.

4. Keep the non-Go code in separate files

Although cgo allows for the whole non-Go code to go in the comments, please, don’t do that. You’ll end up in unreadable code. Check out my repository for a possible solution.

Now what?

I don’t know actually. It really took me 1 hour to get this code compiling and running just for the sake of seeing a Cocoa Window. Didn’t expect much more.
Also, I’ve been doing some work with bindings in the past (Qt – Android – JNI, Cocoa – Qt – C++) and it always gets painful when the main framework is not run in the main thread. I don’t know if this will ever the case with Go. I’m not even sure how far this can be pushed especially when it’s about goroutines and defer‘ed stuff. But, despite not so pleasant past experiences I’d like experimenting this with Go and Cocoa as well.

A question for you

How would you write tests for those bindings?

Please, contribute

If you are any interested in this project, please, shout out loud. That would really help me experiment a bit more. Even if you just want to complain about something terribly wrong I did, please, do!

Cheers.

2 Replies to “Gogoa – Cocoa bindings for Go”

  1. This is actually a great idea…

    About threading and coroutines, there shouldn’t be any problem at all, but if one as to manipulate the ui from another thread then yes, there are problems, but usually there is some routine ou function that allows one to tell the ui thread to do something, like Java Swing invokeLater.

    Now, for mixing Objective C/Swift ARC and Go’s garbage collector, now that’s a different story… Maybe implementing some interface with a finalizer like method, where the user of the library has to call: defer finalizer_name(). In order for the golang to free the associated object…

Leave a Reply

Your email address will not be published. Required fields are marked *

Are you a robot? *