evan_tech

Previous Entry Share Next Entry
07:37 pm, 21 Feb 10

playing with vala

I actually was toying with making something like Vala back in college. It's pretty cute. Much like using the sane subset of C++, as you write code you can imagine what C code is being generated for the code you write; Vala is just automating the boilerplate.

Because they didn't go too crazy with trying to change the semantics of C (it's still possible to write crashing code, for example) your resulting output is easy to understand and with the same dependency set as normal C. Here's an example. To set the cursor on a GdkWindow (corresponds to an X Window) you need the window to be "realized" (which corresponds to being created at the X level). In plain C, you'd hook it up like this:
/* really, this would be lifted out of body of the function */
static void set_crosshair(GtkWidget* widget) {
    gdk_window_set_cursor(widget->window, gdk_cursor_new(GDK_CURSOR_CROSSHAIR));
}
g_signal_connect(widget, "realize",
                 G_CALLBACK(set_crosshair), NULL);
In Vala, I hooked it up like this:
widget.realize.connect(() => {
    widget.window.set_cursor(
            new Gdk.Cursor(Gdk.CursorType.CROSSHAIR));
});
This example shows/implies the sorts of enjoyable tweaks they made: objects are references rather than pointers and are refcounted by default, so you don't have to worry about memory management in 95% of cases; lambdas exist (the "compiler" just hoists them up to top-level functions and reportedly closure-converts); signals are made into a language feature; methods on objects are namespaced to the object's type (so "set_cursor" instead of "gdk_window_set_cursor"); and my favorite of all, enum values are namespaced to within the enum's type name. (Some great features not shown here are simple type inference for variable declarations and the fact that reference types are non-nullable by default.)

Because of these simple semantics, bindings to normal C libraries are effectively just header files, and Vala includes most of the Gnome stack (including Cairo, gstreamer, DBus, etc. but also other stuff like fuse). I rewrote a simple screenshooter app I frequently use at work (so many bug reports to make!) and found it was significantly easier to write and about the same line count as the Haskell one I had written previously. Not because Vala is especially terse, but rather because this sort of IO-call-heavy app needs to be very verbose in Haskell; for example this function has five IO actions in the equivalent Haskell bindings:
Gdk.Pixbuf screenshot() {
    var screen = Gdk.Screen.get_default();
    return Gdk.pixbuf_get_from_drawable(
        null, screen.get_root_window(), null, 0, 0,
        0, 0, screen.get_width(), screen.get_height());
}
It's not a panacea, however; as you'd expect from a source translator, debugger support is pretty weak as far as I can tell (gdb will tell you the line number but all of the variables have been renamed), though at the same time the generated C code isn't very hard to read.

In all, though, I can see why the Yorba hackers are basing their company around it. It sort of reminds me of Go, except without throwing away the whole ecosystem of existing software. It promises to hit a sweet spot between complexity and simplicity.