Name: Dirk-Jan C. Binnema
Member since: 2000-02-15 18:22:10
Last Login: 2008-11-27 09:21:59
Homepage: www.djcbsoftware.nl
24 Dec 2008 (updated 24 Dec 2008 at 17:06 UTC) »
spitfall
Implementing GTK+-widgets and other GObjects in C requires quite a bit of boilerplate code - that's hardly news. One obvious way to deal with that is to use a different programming language. If you're into C++, I can recommend the excellent GtkMM C++-bindings for GTK+. Programming GtkMM feels very natural and follows the C++-idioms; it's easy to integrate with std:: and friends. Also, it's LGPL and pure C++.Another option is Vala. If you haven't heard about it, Vala is a programming language in its own right, with similarities to C#, but specifically designed for use with GObject. One very interesting thing about Vala is that it compiles to plain C-with-GObjects (as an intermediate step). Thus, you write in Vala, with no 'libvala' needed, with code which is just as fast as handwritten C. Vala also supports many other libraries, which can make them easier to use, compared with plain C. Using Vala, writing GObject/GTK+-based applications becomes a lot easier. Vala Overview.
Finally, my truly low-tech solution is spuug. Spuug is a little GObject code-generator that I wrote in 2006 to learn some Ruby, and to save myself some time. And boy, has it saved me some time! Now, finally a new version. The credit for this go mostly to Viktor Nagy (many thanks!), who submitted some patches.
spuug usage is quite easy; for example:
$ spuug --class=FunkyFooBar --namespace=Funky --parent=GtkWidget
Of course, spuug works well for Maemo-code, and I know of a number of programs that are using it.
There are of course some disadvantages to using code-generators. But the advantage of spuug is that it doesn't require you to learn any new language. Also, after using it, you're not depending on spuug - the output is perfectly readable C code.
Syndicated 2008-12-24 15:12:00 (Updated 2008-12-24 16:14:31) from djcb
the song remains the same

The program is listed as the 'official' client for Linux by the NOS (state television), and I'm getting quite some mails -- but interestingly, not one single bug in three years. To be honest, there is a bug remaining: there is too much bad news in the news section. I am working on that one, but it might take a while.
I am also preparing a Maemo-version. Interestingly, I had a version running on an 770 in early 2005 at LinuxTag, but I never got to packaging it. Anyway, the work has to wait until after my trip to a friend's wedding in the Eternal City of Rome, where I'll be flying.
As if all of that were not enough, I started a blog with tips for emacs-users; the idea is to have frequent small posts that show one useful trick: Emacs-Fu. Let's see if I succeed.
Syndicated 2008-12-02 20:04:00 (Updated 2008-12-02 20:21:19) from djcb
it's so easy

:
-b \pm \sqrt{b^2 - 4ac} \over 2a
So what I'd like is a way to use (i) TeX-notation and (ii) have it display correctly in any (graphical) browser. One way to that is to use LaTeX to process and render the formulae, and convert that to a PNG-image. In 2004, I wrote a little tool called WebTeX to create small images from TeX-formulae. It was nothing too fancy; you enter a <img ...>-element with some decription of some formula, and the little tool would turn it into an image, using LaTeX and ImageMagick. I don't maintain that old tool anymore - it was time for something new. Therefore...
<h3>texdrive</h3>
This weekend, I wrote a new maths-in-webpages tool using emacs-lisp. The emacs-integration makes adding formulae to html-pages really easy. For example, if I want to include the famous Bayes' Theorem, I simply type:
M-x texdrive-insert-formula
Formula: $P(A|B) = \frac{P(B|A)P(A)}{P(B|A)P(A) + P(B|\overline{A})P(\overline{A})}$
Title: bayes-theorem
<img src="bayes-theorem.png" title="bayes-theorem"
class="texdrive-formula" name="$P(A|B) = \frac{P(B|A)P(A)}{P(B|A)P(A) + P(B|\overline{A})P(\overline{A})}$"
border="0">

So, for immediate download: texdrive.el. It works pretty well for me; please let me know if you have any problems or are missing something. In some cases, the formulae are not as sharp as they could be; I hope I'll be able to improve it with some tweaking. Anyway, it's nice to see how one can solve problems by glueing together some existing open-source tools. Standing on the shoulders of giants...
Note that some wiki-software, notably Wikipedia's MediaWiki, use a similar approach.
Syndicated 2008-11-26 19:55:00 (Updated 2008-11-26 20:43:41) from djcb
the test that stumped them all
Most of us are not Donald Knuth, and indeed need to test our software. That is even true for my hobby projects - when I offer software for use by others, it's a matter of craftmanship to deliver the best software possible. It's very hard to foresee all the possible environments (architecture, compiler, library version, ...) where my software might be run. But at least, I can minimize the number of programming errors by testing things as much as possible.The trouble with testing, however, is that it is dead boring. I hate doing boring things -- life is just too short. So, I want to do my testing in the least boring way possible -- I'd like to be able to simply run:
$ make test
and have that go through all my test cases, and report any failures. The idea is that if it is so easy to run tests, you might actually do so, and make sure your software is working according to plan. When doing a release, it is so easy to forget something really obvious, for which you get embarrasing bug reports... Running some automated tests gives some peace of mind when doing a release.
<h3>gtest</h3>Since 2.16, the GLib library offers a unit-testing framework called GTest (note, this is not to be confused with Google Test, sometimes also called GTest). GTest is not much different from, say, check, but it's part of GLib and integrates nicely with it. I have started to use it for mu, and I am quite happy with it. Here, I will not go into the details of actually writing test cases, but talk about how to integrate GTest with your code. For the best results, you'd probably want to integrate it with your build system. I am using autotools.
The overall setup is that for all my directories with code, there is a subdirectory tests/ which contains the test code. Those test cases are unit-tests, which test one function or a couple of them combined. Now, of course it's a lot easier when your code is written in such a way that makes this easy[1]. In addition to the per-directery tests/, there is also a top-level tests/, which tests the whole software workflow. In the case of mu, this means that the tests will index some test messages, fill a database with that, and then run some test queries against this database. When all of that works correctly, I am quite confident that my software is not totally broken.
<h3>autotools</h3>Now, let's discuss how you can integrate GTest with your code; this is inspired by the way GTK+ does it these days. First, here is gtest.mk, a file in the top of my source tree, that I include in all Makefile.ams that require GTest support:
TEST_PROGS=
test: all $(TEST_PROGS)
@ test -z "$(TEST_PROGS)" || gtester -l --verbose $(TEST_PROGS); \
test -z "$(SUBDIRS)" || \
for subdir in $(SUBDIRS); do \
test "$$subdir" = "." || \
(cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $@ ) || exit $? ; \
done
.PHONY: test
This blob adds a test target to various Makefiles, which will run the gtester program (part of GTest) with your test programs.
In my configure.ac I have:
# g_test was introduced in glib 2.16
PKG_CHECK_MODULES(g_test,glib-2.0 >= 2.16,
[have_gtest=yes],[have_gtest=no])
AM_CONDITIONAL(MU_HAVE_GTEST, test "x$have_gtest" = "xyes")
if test "x$have_gtest" = "xno"; then
AC_MSG_WARN([You need GLIB version >= 2.16 to build the unit tests])
fi
include $(top_srcdir)/gtest.mk
SUBDIRS= .
if MU_HAVE_GTEST
SUBDIRS += tests
endif
[....]
#include <glib.h>
#include "my-code-to-test.h"
static void
test_num_str (void)
{
char *str;
g_assert_cmpstr (str = my_num_str(1001),==,"one thousand and one");
g_free (str);
g_assert_cmpstr (str = my_num_str(-1),==,"minus one");
g_free (str);
}
static void
test_warning (void)
{
/* no complex roots: my_sqrt(-1) should
* return MY_SQRT_ERROR and issue a g_warning; the
* g_warning will trigger the process to fail,
* which is what we're expecting */
if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
g_assert (my_sqrt (-1) == MY_SQRT_ERROR);
g_test_trap_assert_failed ();
}
int
main (int argc, char *argv[])
{
g_test_init (&argc, &argv, NULL);
g_test_add_func ("/mytests/test-add", test_add);
g_test_add_func ("/mytests/test-warning", test_warning);
return g_test_run ();
}
$ make test
For mu-0.4 I get the following output:
[...]
make[1]: Entering directory `/home/djcb/src/mu-0.4/tests'
TEST: test-index-search... (pid=15553)
/all/test-query01: OK
/all/test-query02: OK
/all/test-query03: OK
/all/test-query04: OK
/all/test-query05: OK
/all/test-query06: OK
/all/test-query07: OK
/all/test-stats01: OK
PASS: test-index-search
make[1]: Leaving directory `/home/djcb/src/mu-0.4/tests'
make[1]: Entering directory `/home/djcb/src/mu-0.4/tests'
TEST: test-index-search... (pid=16024)
/all/test-query01: **
ERROR:test-index-search.c:117:query_01: assertion failed (mu_msg_sqlite_get_subject(row) == "this can't be right"): ("Re: What does 'run' do in cperl-mode?" == "this can't be right")
FAIL
GTester: last random seed: R02S2d24e3907b0c62e6a008e891f401fedf
/bin/bash: line 5: 16023 Terminated gtester --verbose test-index-search
make[1]: Leaving directory `/home/djcb/src/mu-0.4/tests'
Hopefully my setup helps a bit to setup non-boring testing (even though it might be a bit boring in itself...). There are real-life examples of this in both mu and GTK+. And finally, if you find any inaccuracies, please let me know -- there are no unit tests for blog entries to save me from mistakes...
Syndicated 2008-11-11 17:26:00 (Updated 2008-11-11 17:32:07) from djcb
i dream in infra red

Making sure your code is not too complex (according to this measure) means simply assuring that there are not too many code-paths (really: decisions); ie. split your code in to short functions that do one thing, and do it well.
<h3>pmccabe</h3>Now, how do we get the numbers to identify overly complex functions? Thankfully, we don't need to calculate anything by hand. There is the pccmcabe-package (debian/ubuntu) which does the work for us, for example:
$ pmccabe -fv prime.c
Modified McCabe Cyclomatic Complexity
| Traditional McCabe Cyclomatic Complexity
| | # Statements in function
| | | First line of function
| | | | # lines in function
| | | | | filename(definition line number):function
| | | | | |
6 6 18 4 26 prime.c(5): main
6 6 19 1 30 prime.c
An interesting example of complexity is the __strptime_internal in evolution-data-server/trunk/libedataserver/e-time-utils.c, which has complexity of 196(!). I am glad I do not have to maintain that one...
<h3>recommendation</h3>What should be the maximum recommended cyclomatic complexity for a function is debatable - but many coding guidelines suggest a value of 10. If you go much beyond that, it's easy to see that the function gets very complex.
As always we should use guidelines with care. I can imagine some inherently complex algorithms that you nevertheless wouldn't like to split precisely *because* you want to keep things as understandable as possible. But those will be rare exceptions.
<h3>practical</h3>Obviously, limiting cyclomatic complexity is not sufficient to create maintainable software; there are still many other opportunities for making your code hard to understand. Still, it does not hurt to at least keep this one aspect under control, especially as experience suggests there is a high correlation between function complexity and error density. Fortunately, it's usually not too hard to reduce the complexity: split big functions (carefully!) into smaller ones; logical units that do one thing, and do one thing well.
I made sure the new mu follows the <=10-rule. I found some extra targets for Makefiles quite useful for that:
cc10:
@pmccabe `find -name '*.c'` | sort -nr | awk '($$1 > 10)'
cc20:
@pmccabe `find -name '*.c'` | sort -nr | awk '($$1 > 20)'
Syndicated 2008-11-01 10:03:00 (Updated 2008-11-01 12:18:51) from djcb
djcb certified others as follows:
Others have certified djcb as follows:
[ Certification disabled because you're not logged in. ]
FOAF updates: Trust rankings are now exported, making the data available to other users and websites. An external FOAF URI has been added, allowing users to link to an additional FOAF file.
Keep up with the latest Advogato features by reading the Advogato status blog.
If you're a C programmer with some spare time, take a look at the mod_virgule project page and help us with one of the tasks on the ToDo list!