Tag Archives: vala

Vala delegates under the hood

On the Vala mailing list someone wondered if delegates are merely function pointers, not some higher-level concept.  This was in the context of a blog post earlier this year speculating (accusing?) Vala of infringing on Microsoft patents.  I won’t step into the legal morass of software patents under United States law, but it’s important to know: delegates are not merely function pointers.  Understanding how delegates differ from function pointers makes for a better understanding of their power.

Consider the common C++ dictum against taking pointers of non-static functions (that is, methods, which are different than pointers to member functions, C++’s mangled way of dealing with this problem).  A method pointer is near-useless without a corresponding this pointer (which must be manually passed on the stack).  And pointers to virtual methods bypass the vtable, which is itself dangerous for a bunch of reasons.

Delegates solve these problems in an elegant way.  In order to do this, a delegate bundles together a this pointer (which Vala calls the target and is null for a static delegate) and a function pointer.

However, the delegate’s function pointer is not merely pointing at your callback.  Instead, Vala passes a pointer to a hidden delegation function which calls the “real” function.  The delegation function re-sorts the callback’s parameters to move the user data pointer (which can be anywhere on the stack, and is often last in GLib) to the first parameter for the real callback (making it the this pointer).  If the delegate is for a virtual function, this “real” function in turn calls through the object’s vtable (which is a function pointer stored in the object’s instance structure).

These levels of indirection means delegates just work (with some notable exceptions).  Because this binding happens late (i.e. at run-time), you can pass delegates around in constructors before the child class has completed initialization (although there’s some danger there, obviously).  If Vala later adds deeper mixin support, late binding means delegates still work.

What’s cool about Vala is how this is all laid out visibly in C.  Perusing the C code makes it easy to learn how modern object-oriented features are implemented down at the metal.  In essence, Use the Source Luke has two meanings with Vala: you can glean language features by examining the compiler or the code the compiler generates.

Vala and the comma operator

One of the more interesting parts of working on a Vala project is occasionally having to read through the C source the Vala compiler generates.  Sometimes it’s to investigate a bug (maybe your own, maybe the compiler’s) and sometimes it’s just out of curiosity.

Personally, I think the C code Vala produces is pretty darn good as far as machine-generated code goes.  (And I’ve seen some horrible machine-generated code, not including obfuscators and their ilk.  Which reminds me, have I ever told you about when I met Phil Katz?  Another time.)  Certainly I feel I could produce much prettier code by hand, but that’s the point: I would have to do it by hand.  A lazy programmer is a good programmer.

Take a look at this typical example of Vala’s generated C code:

gboolean dimensions_has_area (Dimensions *self) {
    gboolean result;
     gboolean _tmp0_ = FALSE;
     if ((*self).width > 0) {
         _tmp0_ = (*self).height > 0;
     } else {
         _tmp0_ = FALSE;
     }
     result = _tmp0_;
     return result;
}

If an interview candidate at Yorba put this up on the whiteboard, I imagine the first thing we’d ask would be, “Ah … anything you think you could do to clean up this function?”

This isn’t to knock Vala or the compiler or the wonderful work Jürg and Team Vala have done.  And yes, I know, gcc will optimize this down to machine code that would be pretty much like the machine code it would produce if I hand-coded this.  And, of course, unless this is in hot loop (which it’s not, last time I checked), none of this matters anyway.

In short, I lose zero sleep over this.

But consider this line, which is also not atypical:

scaled = (dimensions_floor ((_tmp2_ = (dimensions_init (&_tmp0_, (gint) round (scaled_width), (gint) round (scaled_height)), _tmp0_), &_tmp2_), (_tmp3_ = (dimensions_init (&_tmp1_, 1, 1), _tmp1_), &_tmp3_), &_tmp4_), _tmp4_);

Ah … okay, hold on.  Don’t run off.  It’s not as bad as you think.  It’s just that this makes much more sense to the C compiler than it does to you.

My advice to anyone who dives into Vala’s generated code is to study up on the comma operator.  I suspect most programmers (maybe 98% of them!) have never used the comma operator outside a for loop, and even then, rarely.  Most of them would say that the comma operator is only used to perform multiple statements (actually, “operands” in the parlance) on a single line of code.  That is, it’s a handy way when writing a for loop to squeeze in multiple statements inside each of its three parameters.

Which is true, save for one thing: With the comma operator, the statement as a whole evaluates to the final operand.  Thus, the initializers in this for loop evaluate to 42:

for (i = 0, j = 42; i < j; i++)

The initializer isn’t being assigned to anything, so we don’t notice, so we never learn.

Looking back over that C code up there, mentally weed out the _tmp0_, _tmp1_, etc. and see it for what it is: Initializing two dimensions structs (one goes into _tmp2_, the other into _tmp3_), which are passed to dimensions_floor as parameters, which puts its result into _tmp4_ (whose address is passed to dimensions_floor as its third parameter).  The final operand of the comma operator is, in fact, _tmp4_, which then is returned to scaled.  The comma operator makes all this happen.

Here’s that line in Vala, by the way:

Dimensions scaled = Dimensions((int) Math.round(scaled_width), (int) Math.round(scaled_height)).floor();

Synchronization in Vala

When I first began working with threads in Vala, I was happy to see its lock keyword.  Compare that response to when I wrote my first Java program (wa-aa-ay back in 1996).  I was a bit put off by the synchronized keyword — I still had in me that C-inspired purity that there should be a strict separation between language and library.  I was blind to the idea that critical sections and semaphores should be built into a “serious” language.  I’m sure I muttered something about syntactic sugar and sighed and gave Java threads a try … and loved them.  Critical sections and block-scoped programming really do go hand-in-hand.  It was a joy to know that I could never leave a critical section locked when I exited a function.  That and Java’s intelligent exception handling really sold me on the language.

But when I began coding threads in Vala, I noticed some limitations to the lock keyword.  Firstly (and oddly), the compiler would only allow me to lock member variables of the current object, but not the object itself.  This is perfectly legal in Java:

public void method() {
    synchronized (this) {
        // protected code
    }
}

This is so useful, Java has syntax for locking this throughout an entire method:

public synchronized void method() {
    // protected code
}

So why can’t Vala do something similar?  Why can’t I lock(this) — especially since, if the this variable is a member of another object, that object can lock it!

And I noticed something even odder with lock.  When you synchronize on an object in Java, you’re essentially using an invisible lock() method on the object.  (This is the “intrinsic lock” or “monitor lock” in Java-speak.)  Beneath the covers it’s something like this:

object.lock();
try {
    // protected code
} finally {
    object.unlock();
}

You can see why this will compile in Java but produce its ill-named NullPointerException:

Object object = null;
synchronized (object) {
    // ka-boom
}

However, this code works just fine in Vala:

class Foo {
    Object object = null;
    public void go() {
        lock (object) {
              // smooth sailing
        }
    }
}

What’s the story?  If object is null, how can it be locked?

It turns out that Team Vala have come up with an interesting paradigm for locking variables that (a) works around certain limitations of GObject, and (b) actually cleans up some of my issues with Java-style critical sections.

The key to understanding the lock operator in Vala is to understand that you’re not locking the variable itself.  You’re locking the memory used to store that variable. That’s why Vala can only lock member variables of a class.  The only other storage to lock is the stack, which is rarely (if ever) useful (and probably indicates a design flaw), or global memory, which isn’t such a hot idea either.  (Locking a static member of a class is allowed.)  Jürg discussed this on the Vala mailing list.

Like Java, lock is calling a “magic” reentrant mutex that’s associated with the member variable.  This mutex cannot be reliably passed around with the variable (which would be necessary for code in another class to lock it).  And GObject doesn’t provide a built-in object-wide mutex that Vala can use.  Vala could magically generate one in your own classes, but lock wouldn’t work on any non-Vala generated GObject — including GTK, GLib, and so on.  Hence, this rule is also a nod to the limitations of the libraries Vala is building upon.  To put it another way, lock always works because it can only lock Vala-produced objects.  Ta-da.

And you can lock native types, not just objects.  Locking an int counter is a snap in Vala without resorting to Java’s coarse-grained synchronized(this) or a dummy Object.

Another advantage to Vala’s approach is that it solves one of my gripes of Java synchronization.  Going back to the analogy I mentioned earlier, every Object in Java has an invisible lock() and unlock() method — but those methods are public.  Anybody can lock an object and hold that lock during their six-deep nested loops or blocking calls, even if that lock is relied upon elsewhere in the system (by, say, a thread that very object created and maintains).

Vala doesn’t have this problem.  A member variable is only lockable by methods of its class.  Problem solved.

And go back to the other example, where Java will throw a NullPointerException when synchronizing on a null object.  Because Vala is locking the storage of the reference, and not the reference itself, you can do this reliably and easily:

// atomic singleton creation
lock (object) {
  if (object == null)
    object = new Object();
}
// atomic replacement of multiple fields
lock (object) {
  object = new_object;
  object_modifier = new_object_modifier;
}

You can do the second one in Java, but it’s probably not what you want — most Java programmers will synchronize on this, which may be too coarse.  The only alternative is to generate a dummy Object to lock upon, which is kind of ugly.  Nice and clean in Valaworld.

Vala and C warnings

We’re frantic here at Yorba working to get Shotwell 0.4 out the door before the holidays, but I wanted to take a breather and point out a positive trend I’ve noticed with the Vala compiler.

As you may or may not know, Yorba is a 100% Vala shop — well, maybe not 100%, but the sliver of code that’s not Vala (and I’m including Make as a kind of scripting engine) is present only out of necessity.

We were sold on Vala from just about the beginning of Yorba’s existence.  One major concern was the number of C warnings gcc spat out when compiling valac’s generated source.  I’m from the medieval school of thought where Wernings Shalt Be Treatyd As Errours, but unfortunately there’s little recourse with a system like Vala.  Each warning had its own root cause.  There was no central fix that could be made to the compiler, nor was it a simple matter of rewriting the offending line.  Many warnings were due to const-correctness.

Recently I’ve noticed fewer warnings than ever.  Shotwell is approaching the 25,000-line ceiling (according to wc, blank lines stripped) and I was curious what kind of trend there’s been on warnings.  It’s positive all right:

18-Mar-2009 Vala 0.5.7: 746 lines, 4 warnings, 0.54% lines generating warnings
12-Apr-2009 Vala 0.6.1: 2,789 lines, 8 warnings, 0.29%
20-Apr-2009 Vala 0.6.1: 3,160 lines, 11 warnings, 0.35%
26-May-2009 Vala 0.7.3: 6,347 lines, 57 warnings, 0.90%
28-Jun-2009 Vala 0.7.3: 8,663 lines, 79 warnings, 0.91%
18-Sep-2009 Vala 0.7.5: 15,270 lines, 131 warnings, 0.86%
17-Dec-2009, Vala 0.7.8: 24,591 lines, 56 warnings, 0.23%

I suppose I could go crazy with the graphs, but you get the point: Shotwell’s code size is growing and the rate of warnings are dropping.  The big leap was between 0.7.5 and 0.7.8, which justifies my hunch that this was a recent development.

(I ran 18-Mar for giggles.  I don’t think a program under 1,000 lines is worth measuing in this context, but it’s fun to remember when Shotwell was just a tot.)

Zero warnings are, of course, the final goal here, but I’d say that Vala’s largest improvement of late has been its growing silence.  When you think about it, that’s what you’re really wishing for when you type “make”.