Binary Badass

goto and you

by eanx on Dec.15, 2008, under Open Source

Like most people in the open source community, I want to try to give back something to the community; be it in the form of a code refactoring that greatly simplifies or modularizes something to just learning more about how things work. In my quest to learn more about programming and computer science in general, I’ve been intrigued with the use of the goto construct in the Linux kernel and open source software in general.

In the Ubuntu-distributed source for Linux 2.6.24, there are 50,295 occurrences of goto in the kernel code:

eanx@crocostimpy:~$ grep -R "goto" /usr/src/linux-source-2.6.24 | wc -l
50295

Edsger Dijkstra who is perhaps best known for his shortest-path algorithm, was a vehement opposer to the use of the goto construct made; A Case Against The GO TO Statement.

This question is frequently a topic found on Linux kernel hacking mailing lists. Linus himself offers a pretty good explanation of why you they’re good form for certain applications. One good reason he gives is breaking out of the middle of deeply nested conditional statements and for very rarely used exceptions. Remember, C doesn’t have a try-catch construct. Another reason given is that it enhances readability and therefore maintainability.

That said, I was curious about a few things. So I recently downloaded the source for the Pidgin IM client, version 2.5.2.:

eanx@crocostimpy:~$ grep -R "goto" pidgin-2.5.2 | wc -l
285

There are 285 occurrences in Pidgin and so naturally, I got a little curious to see if I could maybe refactor a few of them out of the program altogether and I discovered this amusing comment in ./libpurple/dbus-server.c in purple_dbus_iter_has_table(). I immediately thought, this is one of the joys of open source software; reading the comments!

367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
GHashTable *
purple_dbus_iter_hash_table(DBusMessageIter *iter, DBusError *error)
{
	GHashTable *hash;
 
	/* we do not need to destroy strings because they are part of the message */
	hash = g_hash_table_new(g_str_hash, g_str_equal);
 
	do {
		char *key, *value;
		DBusMessageIter subiter;
 
		if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_DICT_ENTRY)
			goto error;
			/* With all due respect to Dijkstra,
			 * this goto is for exception
			 * handling, and it is ok because it
			 * avoids duplication of the code
			 * responsible for destroying the hash
			 * table.  Exceptional instructions
			 * for exceptional situations.
			 */
 
		dbus_message_iter_recurse(iter, &subiter);
		if (!purple_dbus_message_iter_get_args(&subiter, error,
				DBUS_TYPE_STRING, &key,
				DBUS_TYPE_STRING, &value,
				DBUS_TYPE_INVALID))
			goto error; /* same here */
 
		g_hash_table_insert(hash, key, value);
	} while (dbus_message_iter_next(iter));
 
	return hash;
 
error:
	g_hash_table_destroy(hash);
	return NULL;
}

When all is said and done, it is a useful construct if you understand the consequences and tradeoffs. Like everything else in computer science and software engineering, the dos and do nots should be studied and understood.

No comments for this entry yet...

Leave a Reply