Archive for July, 2009

Code documentation is really important

One of the things I learned about during my continuing involvement in Kolf is the importance of code documentation. All of you will know user documentation (handbooks, tooltips, …), and developers know about API documentation. But developer documentation is also happening on a more abstract level. It doesn’t help if you understand what single functions do, if you do not get the big picture. How do these classes work together? And which class should I use in the code I’m working on?

These questions were exactly the ones I couldn’t answer when I was looking at the source code of Kolf 1. It might have been that I could get into it with enough time and will (it seems doable), but you see: Missing developer documentation raises the entry barrier.

I was enthusiastic to get proper, extensive documentation in Kolf 2. From the start, every class API has been documented (the obligatory lower level of developer documentation). Unfortunately, the high level documentation was going very slowly until last weekend. When I started to refactor some internals, I set the private goal to not proceed with the refactoring until I documented the last part. Currently, I’m working on documentation for the basements of Kolf, which look like this:

Class layout in Kolf 2 (cut-out)

Class layout in Kolf 2 (cut-out)

I would like to encourage every developer out there to write high-level developer documentation, to be sure that work on his code can continue even if he is not available anymore. Writing documentation is also a good opportunity for reflections on the class layout and the semantics of the classes.

P.S. You might’ve noticed that above graphics uses TeX fonts. It’s actually written in LaTeX (with PGF/TikZ), the sources are in SVN at trunk/playground/games/kolf-ng/doc (view in WebSVN), where the complete documentation is located (see the README for how to compile).

Comments (1) »

Kolf: Much progress, no screenshots

Yesterday, I had my last exam. Today, I broke Kolf. During this interesting experience, I managed to establish a new record: Revision 1001908 changed 66 source files (which is about the half of Kolf). I tried to break it into multiple commits, but it did not work out: I have refactored one of the central classes to not be a singleton anymore, thereby also shifting the semantical meaning of some related classes.

The result was like an earthquake: Although it happened at a quite distinct point in the code, it caused structures to fall apart everywhere. Now nearly everything is working, only the course boundary does not load properly. (I know what the problem is, but I’m too tired for the solution right now.)

The sad thing about structural changes is that the benefit is a priori only visible to the developers. I hope that the clear structure I’m building for Kolf 2 will help other developers understand it when I’m not available for maintenance anymore. Apart from that, some of the changes I’m making now allow for more interesting features to be added.

In other news, Kolf’s GSoC student Zeng Huan is working on the first bits of a heightmap editor right now. Again, it’s too early to show screenshots, but expect screenshots and more information to appear here over the next weeks.

Leave a comment »

Sign this petition!

This is for all German citizens out there: Please sign this petition on the Bundestag webpage. I want the Bundestag plasmoid on my desktop!

Comments (3) »

Shutdown your machine automatically (or from remote)

I was wondering whether it is possible to shutdown a KDE 4 session programmatically. The obvious solution is “sudo shutdown -h now”, but this requires me to enter my root password. The manpage shutdown(8) mentions a file /etc/shutdown.allow which could define users allowed to shutdown the machine, but this does not seem to work. (I put myself into that file, and shutdown keeps telling me that I must be root to do that.)

That was too much of a hassle for me, so I looked for a KDE-ish solution to the problem. And whenever you need to access KDE functionality from the command line, DBus is your friend. I quickly found on the session bus the org.kde.ksmserver service, which contains no shutdown() method, but a logout() method. Technically, both things are fairly similar, so let’s look into this method: Okay, it takes three int parameters. What would MacGyver do now?

I eventually found what these parameters are. Reading the code of KSMServer and the KWorkspace library, the three parameters are values from the enumerations KWorkspace::ShutdownConfirm, KWorkspace::ShutdownType, KWorkspace::ShutdownMode (in that particular order). The possible values for these enumerations can be found in the API documentation for KWorkspace. For example, to shutdown your machine from the command line, say:


$ qdbus org.kde.ksmserver /KSMServer org.kde.KSMServerInterface.logout 0 2 2

The parameters mean that, without confirmation (the 0), the machine should be shut down (the first 2) immediately (the second 2). So if you ever wanted e.g. to shutdown your machine from remote, now you know how to do it. (Perhaps this could be put on one of our wikis, but I’m unsure which one of Techbase and Userbase is the right one, and where to put it there.)

Update 1: Milian Wolff correctly mentioned in the comments that KShutdown simplifies this task very much. I had also used KShutdown in KDE 3, but had forgotten about it because the port was not done when I switched to KDE 4 as my main desktop.

Update 2: A commenter asked for a more detailed guide on how to get to such information. As an example, I’ll show you how to find the command that toggles KWin’s compositing: (I know of Alt-Shift-F12, but one might want to do this in a script)

  1. Call qdbus without parameters to get a list of all registered services. Tthe numerical names such as “:1.42″ can be ignored, as most programs register more readable names such as “org.kde.ksmserver. Some of thesed named services have some numerical suffix, this is the process ID for applications which can have multiple instances at once.
  2. When you’ve found the right service, give its name as the first parameter to qdbus. In this example, you would then invoke “qdbus org.kde.kwin”. qdbus will now print all interfaces in this service. All KDE applications have a “/MainApplication” interface to control the application in a generic name. (This generic interface is used by kquitapp, for instance.)
  3. Pass the name of the right interface (“/KWin” in our case) as the second parameter to qdbus. Now, you’ll see an extensive list of all methods and signals that this interface provides. While signals allow the service to pass information to its clients, methods allow to invoke certain things in the service. In our case, the right method is:

    method Q_NOREPLY void org.kde.KWin.toggleCompositing()
  4. Add the name of the method, which is “org.kde.KWin.toggleCompositing” in the above example, as the third and last parameter to your final qdbus call. If the method in question has arguments (like the above “org.kde.KSMServerInterface.logout” method), give these in the right order as further arguments. (Of course, you have to know what these parameters mean, which was not that apparent in the KSMServer case.)

Comments (11) »

Much thx to Ian Wadham!

In one of my last posts I indicated that Kolf 1.9 could possibly not be released with KDE 4.3 because it fails to load its objects. The same panic was expressed by me on the mailing list, and (as usual ;-) my plans worked out: My panic made Ian Wadham, one of our kdegames hackers from Australia, dive into the Kolf 1.9 code (that pile of mud I talked about earlier) and find the cause of the bug.

The problem was that Kolf was relying on some unspecified behavior of KConfig::groupList(), which returned a sorted list of group names in KDE 4.2, but not in KDE 4.3. Such a change is of course legitimate, because the KConfig developers never stated that KConfig::groupList() would return a sorted list.

If you’ve got a current trunk snapshot (I think the fix is in trunk since yesterday), please check whether Kolf can correctly load holes (not only the first hole of a course, but also the following ones!). If you run into problems, please write to the kde-games-devel mailing list quickly. Thanks.

Comments (4) »

Marketing Internet Explorer 8

I’ll leave it to you to judge Microsoft’s marketing campaign for Internet Explorer 8. I just thought you would like to know it, as well as the outtakes.

Comments (1) »

Python experiences, or: Why I like C++ more ;-)

So I’ve been coding some Python lately, because this is the language of choice for the “Computational Physics” course I’m attending. As the name says, it is more about physical and numerical problems than about programming, and the instructors chose Python as it’s easy to get into (most Physics students had not coded up to now).

I was quite excited about that, as I have wanted to learn Python for about a year. The fact that the course has its own mailing list where students can ask questions to their fellows (and, of course, the teachers), allowed for some insight on how beginners in programming get into Python.

First off, Python is mostly good for beginners. “print” works on almost everything, and allows you to very easily inspect your program. You can load your work-in-progress code in IPython, and inspect the values of the computations. (I must admit though that I never used this feature, I’m just too used to inserting “print” statements everywhere and re-running the program.)

In the course of the course (pun intended), the only problem that many people ran into was copy-by-reference. When you’re working on some numerical problem, you’re dealing with number arrays most of the time (we were instructed to use NumPy, together with matplotlib for graphical output). And those are, unlike simple numbers, copied by reference. If you say “b = a”, where a is an array, and then modify the contents of b, you’ll also modify a, as b is just another name for a. The solution is “b = 1 * a”. The multiplication operation causes a deep copy of a to be created.

A big mistake which I (as a senior C++ programmer) did often in the first few weeks is the excessive usage of for-loops with numpy arrays. For example, the following two code pieces are equivalent:

a = numpy.ndarray((N, N))
for x in xrange(N):
    for y in xrange(N):
        a[x, y] = x ** 2 + y ** 2
# or
a = numpy.arange(N)[:,newaxis] ** 2 + numpy.arange(N)[newaxis,:] ** 2

On the first look, the first one looks more well-arranged than the second one (given we do not worry about the double parentheses), but the first one is sllllllloooooooowwwww. For N = 2000, the first one needs 4.16 seconds on my system, while the second one is processed in 0.03 seconds. The simple reason that the for-loops in the second codes are hidden deep in Numpy’s implementation, which is done mostly in C (and some Fortran). In an actual example, I had to compare the numerical precision of various discrete integration algorithms. The first version needed 16 seconds to calculate everything and start up, and after transforming all for-loops into Numpy operator expressions, the startup time was reduced to 2 seconds (most of this time was actually spent on loading all modules and initializing matplotlib).

But even this is just a problem of how accustomed you are to an API. I would not say that Python is inferior because it takes ages to execute for-loops in Python itself, rather than in underlying C libraries. Rather, Python is an elegant wrapper on top of many nice libraries, which helps to greatly reduce boilerplate code. Or, as I said to a fellow student, “every scripting language has its use case: Perl has extremely fast string operations, PHP is for website coding, and Python is for extremely rapidly escaping back to C code”.

Today I’ve been working on my final project. (We have to build a bigger application around some numerical or physical problem and present it to the rest of the class.) This has mostly been fun, as this was the first time where I could escape to well-known APIs through the magical key called PyQt4. While I’ve been working on this project, I finally found a way to criticize Python: It’s not optimized on escaping back to C++ code, because the OOP concepts in Python and C++ are, well, completely different things. In C++, classes are blueprints which can be used to create objects. Compare it to civil engineering: Using a construction plan, you put together various materials until the building has emerged.

In Python, a class is essentially a special type of object that works as a function. When this class function is called, it creates a copy of itself and calls the __init__ method of this copy. Here we see that these concepts do not quite fit: It’s like one would just copy the construction plan of a building, lay it out at the building site, connect an air pump to it, inflate it and hope that a building emerges.

There is nothing bad about the class concept in Python in general, the bad thing for me is that it does not match my perspective that I gained to OOP in the last ~10 years. And because it does not match the OOP model in C++, creating bindings seems to be more complicated. For example, I could not create a class that subclasses QObject and QGraphicsItem (a pattern which I regularly used e.g. in Kolf, to get a 2D representation together with signals/slots and properties), and I could not create a Borg-style class that derives from QTimer.

Apart from that, my criticism of Python sums up to missing explicit namespace declaration (why am I bound to file and even directory structure here?) and missing visibility modifiers for class members (“public”, “protected” and “private”) and, most prominently, that duck typing.

The last one is usually destined to be discussed most controversial, so I’ll just neutrally put down my two cents on this topic. If I can choose, I’ll only use strongly typed languages, as in: languages where each variable has a fixed type and unsafe conversions are not allowed, just because it eliminates a very big mass of problem sources. Actually, I would like a programming language which ensures that the most problems do never happen to me (i.e. a strongly typed language with garbage collection, bounds checking and stuff) _and_ runs fast, with very little overhead, and always with the possibility to bypass these checks if the overhead becomes too big. Sadly, I do not know of any language currently in existence that offers me such things.

I do not feel that I’m at a good point to end this blog post, so I’ll just show off some random bling-bling from my Python code at the end: The actual goal of the project is to implement simple pathfinding with genetic algorithms. That means that you start with some random paths, kill bad ones, and mutate and combine the good ones to produce possibly better paths (you know, “survival of the fittest”). I decided to make the thing a bit fancier by allowing obstacles to move around during the calculation, to see how the population reacts on them. This was the perfect moment to try something I’ve wanted to try since a long time: a fluent programming interface. These are programming interfaces where the statements read like sentences:


s = SimulationArea(500, 500)

s.addObject(WallObstacle(400, 0)
    .moveTo(-200, 100).immediately()
    .standStill().forSeconds(2)
    .moveTo(200, 100).forSeconds(5)
)
s.addObject(WallObstacle(400, 0)
    .moveTo(700, 200).immediately()
    .standStill().forSeconds(2)
    .moveTo(300, 200).forSeconds(5)
)

“Hey, wall, move to (700, 200) immediately, wait there for 2 seconds, then move to (300, 300) over 5 seconds.” You get the trick?

If someone’s interested in the full code (once it is finished), I can put it up somewhere (although it will be uninteresting for most of you).

Update: Mh, this blog post got much longer than I intended.

Comments (38) »

Kolf: Creating a terrain texture, and the 4.3 release

A long time, I haven’t written about Kolf. I’m not having any time for coding lately, but Zeng Huan, our GSoC student, has made progress on the automatic generation of terrain textures. The code for that is not in Kolf at the moment, we have decided on him working on it in a separate test bed, the kolf-textureblender:

kolf-textureblender1

In other news (which might be more interesting for most readers at the moment), Kolf in KDE 4.3 is broken. The first hole of every course loads fine, but on the following holes, only one object will be displayed (which is definitely too less). Mauricio Piacentini looked into the code, but didn’t find anything. He meant it looks like Kolf is trying to re-use objects from previous holes, but some changes in Qt 4.5 seem to interfere with this technique very badly. If no one finds the bug quickly (which will likely not happen, as the code of Kolf 1 is a total mess), it is quite realistic that we will have to remove Kolf from KDE 4.3.

If this bothers you and you want to help Kolf return in KDE 4.4 as Kolf 2, please join our team! Write to the kde-games-devel mailing list for more information.

Leave a comment »