Hacker News new | past | comments | ask | show | jobs | submit login
Gotk3: GTK3 the Go way (conformal.com)
111 points by djpressplay on July 16, 2013 | hide | past | favorite | 56 comments



Glad to see some more work being done on UI frameworks in Go, though I doubt this will end the splintered nature of all the different (mostly half-baked, honestly) options.

I've personally been using a Qt5.1/QML based solution with a Go/CGO based QML plugin that acts as a bridge between QML and backend Go code. It doesn't try to export much of Qt to Go, it basically expects you to write the UI logic in QML/QtQuick and then just use Go for the underlying app logic, using the QML plugin bridge to allow Go code to call QML functions and vice-versa. In practice this works somewhat like writing a Go server that manages an HTML UI for doing browser-based UIs with a web-based RPC system, except I can write the UI code in QML which I find much preferable to HTML/JavaScript (variable binding Just Works, no need for frameworks like Angular, no need to mess with CSS, can efficiently pass around binary data in byte arrays easily, etc).

Currently my solution isn't even half-baked, I've been implementing it to serve a specific app, and it currently has some dependencies that force it to be Windows only (these could be trivially removed, but doing so isn't important for my app). I may share the code for this sometime in the future after it has matured a bit more, though there's really not that much to it.


I'd also love to see some source to get an idea of how this works and what the binding code you end up writing looks like.


QT+Go can prove to be an awesome combination. Really hope you release a preview soon.


That sounds interesting, I'd like to see how that's done.


Slightly off topic, but something I've been curious about. Go decided on garbage collection to manage memory. Why do so few languages offer something like C++'s RAII?[1]

In C++, when you define a class, you define the constructor(s) and the destructor. Then the destructor is called whenever the object goes out of scope. Easy. This is the gist of RAII. Furthermore, in C++, a default destructor is automatically generated for you, which will ensure all the objects members are destructed with your object,[2] so you can avoid even worrying about the destructor.

Yeah, it's not as simple as GC, but it seems like a great compromise between manual memory management and garbage collection.

[1]: http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initial...

[2]: Provided no members are dynamically allocated. If you allocate an array in your constructor, for example, you need to free it in the destructor. You need to define a destructor to free dynamically-allocated memory, or to do other cleanup.


Preferring RAII over garbage collection is the decision that Rust made.

Probably the reason that more languages don't use RAII for memory management is safety. C++, even with RAII, is not safe—you can violate memory safety with certain uses of references and iterators. Rust has to go to great lengths (lifetimes and the borrow check—things that have only been in the research landscape) to make this safe.


I'm actually a huge fan of Rust's memory model and wished Go had something similar, since it's faster to use smart pointers, and less calls to the garbage collector are required. I also love how rust uses three different kinds of pointers depending on how the memory is managed, and although it adds some complexity, it gives more semantic value to the data you are working with.

Unfortunately for me, the rust compiler is written in rust, so I would have to adventure to grab a Linux and try my hand at a cross compile before I can play with it on my OpenBSD box.


Or just install it on a Linux VM!


This approach starts getting brittle when you get into objects that aren't procedure-scoped; for instance, a global session table in a web application, or a request token tracker in an RPC system. These are also the kinds of object lifecycles that tend to be behind leaks and corruption in programs that don't use RAII.

People use shared pointers to mitigate that problem, but shared pointers are (a) a reference counting scheme with all the attendant problems and (b) not compatible with code that holds references but doesn't speak the same shared pointer scheme.

(It's been a bunch of years for me since I wrote C++ professionally; that may show here.)


I think the biggest fans of RAII are those who use it more academically -- in real life it is brittle and scopes are tricky. It is also just an idiom as compared to a compiler feature. And, IMHO, RAII tends to play poorly with others.


RAII is of great pratical use and is not just about memory management. My current favourite use of RAII is QMutexLocker:

https://qt-project.org/doc/qt-5.0/qtcore/qmutexlocker.html#d...


It's more error prone than GC and there aren't really enough advantages to RAII to make it worth it much of the time. Sometimes, sure, but GC is nicer and usually fits the bill.


How is it more error prone than GC?


Are you asking what kinds of errors RAII-style C++ programs make that you can't make in Golang (an easy question), or what kinds of errors you can make in Rust that you can't make in Golang (harder)?


I'm just questioning the assumption that RAII as a concept must be memory unsafe, specific language aside.

Edit: To be clear it's the latter question, but more general. C++'s implementation has many opportunities for errors, but I do not think the technique is inherently unsafe. (PL research has proven many similar systems based on unique types and borrowing to be type- and memory-safe.)


It leaves more in the hands of the developer (some would call this "power"), which presents opportunity for programmer error.


A safe RAII system based on unique types is precisely, by definition less powerful than GC, because it allows no operations that GC doesn't allow but forbids some operations that GC allows (namely aliasing).

If you're talking about C++'s unsafe implementation of RAII, that's true of course.


C++ is in fact where my experience with RAII comes from. Could you, for example, forget to make a destructor virtual in "safe" implementations of RAII?

Perhaps the real answer to "Why isn't RAII more popular?" is that C++ has poisoned the well for many programmers.


> C++ is in fact where my experience with RAII comes from. Could you, for example, forget to make a destructor virtual in "safe" implementations of RAII?

No, that would be unsound.

> Perhaps the real answer to "Why isn't RAII more popular?" is that C++ has poisoned the well for many programmers.

Totally agreed. (But that said, I think that Go, and most other languages, made the right decision when going with pervasive GC. It makes the language much simpler, both in terms of implementation and interface. It costs some performance, of course, but being as fast as C in all cases was never a design goal of Go, according to the FAQ. The complexity, both in interface and implementation, that languages buy into if they want safe manual RAII-style memory management is not trivial.)


I am on ubuntu raring with the packaged golang and I can't compile your example code, copied directly out of Sample Use.

  kbarrett@vernon-linux:~/go-work/gotk$ go version
  go version go1.0.2
  kbarrett@vernon-linux:~/go-work/gotk$ go build
  # github.com/conformal/gotk3/glib
  glib.go:380[/tmp/go-build210667265/github.com/conformal/gotk3/glib/_obj/glib.cgo1.go:370]: function ends without a return statement
  glib.go:743[/tmp/go-build210667265/github.com/conformal/gotk3/glib/_obj/glib.cgo1.go:741]: function ends without a return statement
function ends without a return statement. If this is a problem with my version of go, I will try and fetch the latest head from git. I am interested!

sudo go get github.com/conformal/gotk3/gtk -- gives the same error.


Go 1.1 improved its analysis of whether a function ends with a return statement: http://golang.org/doc/go1.1#return


Yes. I think that syntax became legal in 1.1.


I see, ubuntu's go is very old. You can tell I'm not doing this stuff every day. (It's obviously because I'm on a release from April...)

I'm going to try it on FreeBSD.


(That worked.)


If you want the latest Go version on Ubuntu : http://blog.labix.org/2013/06/15/in-flight-deb-packages-of-g...


You can also just build tip on your own locally. Go has virtually no hard dependencies other than gcc (and mercurial to get the repo, unless you pull the code some other way).

  hg clone http://code.google.com/p/go
  cd go/src
  ./make.bash
(or ./all.bash if you want to run all the unit tests)

Same holds true even on Windows if you have a local gcc like MinGW (the only notable difference is you'll execute make.bat instead of make.bash if you're in a Windows cmd shell instead of bash).


Google also distributes binaries for Linux, for me all I do is unzip the file and set up my .profile to look for go in the path it was exported in..I set this up on a per-user basis but it works fine for me.


I was kinda meh on Go (reminded me of my days in the Ada code), but making native GTK Apps seem really interesting to me. Will have to check this out.


I'd say both Go and Ada are much nicer than C and C++ though :P


I have a dream of something like this working with Go's cross-compiling (http://dave.cheney.net/2013/07/09/an-introduction-to-cross-c...) allowing me to build native executables for windows from linux with GUIs.

From poking around, still a pipe dream for the moment.


No mention of goroutines or concurrency in the post. Is it addressed by the project at all? I can't imagine that the GTK main loop will deal well with being cooperatively scheduled -- the UI would block any time another goroutine ran on the same OS thread.

Ideally the GTK main loop would run in its own OS thread, and there would need to be a way to ensure that no GTK calls happen in other goroutines. Other (threaded) environments tend to handle this by deferring via a one-off "idle" function that is scheduled and run by the GTK main loop for things like that.


We do try to deal with concurrency and goroutines as much as we can. I'd recommend taking a look at the (rather simple) goroutine example as part of the gtk package. Unfortunately though, as you said, GTK is not thread safe (calling GTK from multiple threads was deprecated as of the last release I believe) and calls must be made using glib.IdleAdd() to run the functions in GTK's main loop context.


Does anyone else think we need a new open-source widget toolkit? Qt, GTK, and what else is there? Those guys are old. I've done both, and WPF, and WPF is just so much better. I wish there was an open-source toolkit that didn't just suck.


Yes, most are old and tiered. But another problem is, there is not a company/organization or even language community to take on such a big endeavour.

I'd like to see a C based toolkit, that's made specifically for wrapping it up for other languages (in C++, Ruby, Python, Go etc) and has niceties to help with this.


> I'd like to see a C based toolkit, that's made specifically for wrapping it up for other languages (in C++, Ruby, Python, Go etc) and has niceties to help with this.

This is exactly, why GTK+ and essentially the whole GNOME stack is now introspected with GObjectIntrospection. So, there you have it.


Newer versions (4.7 - 5.1) of Qt are really nice and you have many levels of interaction.

1. Standard C++ ui designed in a form designer and connected to C++ classes.

2. QML + javascript.

3. OpenGL with the ability to use widgets on the OpenGL viewport.


How is this different than this? https://github.com/norisatir/go-gtk3

They also set finalizers.


In short, we weren't aware of the project.

I just gave it a try now, but the code will not compile on my dev box (OpenBSD, go tip). Even after making some minor fixes (I fixed an #include directive, removed a call to a deprecated function, etc.) there appear to be some serious issues (one error I got mentioned the size of an array being negative).

It appears this code has not been updated in a year, and we wished to target a recent GTK version (3.8, to be precise) with our bindings. Had we known about the project, we probably would have considered submitted patches to fix its issue and bring it up to date with newer dependencies, but even then, I feel that it would be almost as much or perhaps even more to fix and verify an unfamiliar and broken code base than rolling our own.

But I'm glad to see this project seems to be doing memory management in a Go-like manner.


Just to be clear, this isn't my project, but it has been working fine for me for awhile now, but I am probably not exercising the same pathways as you. Anyway, I have written additional bindings for the Gtk Docking Library and the Syntax Highlighter against this project. Everything compiles, runs, and works well.

It is a little frustrating as it is one of the first projects that comes up when searching for "go" and "gtk3" on Google. So, it is is an alternative to what you are doing I guess.


Actually, some of my coworkers had tried it previously and couldn't get it working either. I just didn't know they had tried it, and they didn't ask me to play around with it to try and get it in shape (this may have been before I started working full time with Conformal).

So this was just me not being aware of it, but others of us at Conformal were, and due to the above issues we decided to do our own.


Are channels and CSP failing as the favored design approach? I keep seeing frameworks that just seem to use Go as if it were C with closures.


That approach isn't too surprising when the Go framework is, like this one, a Go wrapper on top of existing C code. And quite a lot of Go frameworks are that.

However, even ignoring the CGO-based frameworks, there's nothing wrong with mostly using Go as if it were C with closures (and garbage collection, and interfaces, and optional implicit typing and reflection), that's how most Go code looks, even in the standard library. Channels/CSP are great if you need to easily pass data among concurrent goroutines, but not all code neatly fits into that model nor benefits from concurrent execution.

One of the early mistakes most newbie Go programmers make (and I did this myself as well) is overusing channels, just because "hey, channels are super cool"!


You are not considering that most Go UI frameworks are twenty years of C/C++ and a couple months of Go. Naturally anything trying to do significant reinvention is not going to be as far along.


I use channels all the time in actual code using gotk3. Unfortunately, it means using glib.IdleAdd() a lot (because GTK is not thread safe), but it works.


People just lean to their comfort. I am an Erlanger -- so I tend towards channels. As people start doing more concurrently and the problems get more complex, dividing work among simple actors (or microservers depending how you break it up) becomes a great way of keeping complexity under control.


There is probably a large set of developers coming to go for whom that is a lot more natural from familiarity.


Nice! Have this queued up to look at after work. :)


Hmm, does the name "GTK" mean "Gnu Tk"? I thought this was "Go Tk" for a moment when I read the title.


GIMP toolkit, as in the graphic package.


it is gimp isnt it.


if you look on github, you'll notice that all the obvious names were taken, e.g. go-gtk, go-gtk3. that was what really drove the project name to be gotk3.


gnome tool kit. Note that gnome is pronounced gi'nome just like gnu is pronounced gi'new.


gimp toolkit. gtk is older than gnome and was made by the gimp devs.


I still remember Gimp's first release. Uhm, I guess I'm getting really old.


I was thinking of writing a small aplication, originally I was going to use Python... but might as well try this. Thanks.


Just tested on win7 and everything works great! Really nice work.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: