When you don’t trust Strings…

A few weeks back Eskil and I traveled to JavaZone, the biggest Java conference in Scandinavia, and Trolltech had a booth there and I did a presentation. We also got to meet several of our Qt Jambi users. Its always cool to see and hear what people are doing with the tools your developing and there are some pretty cool Qt Jambi things happening out there ;-)

Anyway.. One thing that came up when talking to people was that our signal / slots connections seem dangerous. So when it comes to the piece of code that looks like this:

ui.lineEdit.textChanged.connect(this, "setText(String)");

one sees the String and thinks that, if there is a typo there, my app is busted. Well... it would be if that piece of code wasn't tested. Luckily most signal/slot connections are set up during object initialization, so that a typo here would be detected as you develop your class. Most development is done in a cycle of "develop and test and again", so in practice this is mostly not a problem. And of course, we all know that developers never write errors in strings anyway, right? ;-)

Another problem that one will find with the current string approach is that it doesn't give live feedback and syntax completion in IDE's like Eclipse or IntelliJ. (Interestingly enough, it does in emacs, because my emacs completion is based on recently parsed strings instead of the actual code, which means it always completes something, though with a 5% error-ratio). So you have two problems with the current approach, first that Strings don't feel save (even though they mostly are) and that they don't give you live feedback. Internally we came up with an alternative quite some time ago and have been mentioning it to people who have asked, but I think its time to publish it.

The idea was to introduce a class QSignalHandlerX which offers complete compile-time type checking and offering better support for live feedback in IDE's. The QSignalHandlerX class should have an abstract method that you had to reimplement, which did take correct types as parameter. Based on this you could create anonymous inner classes on the fly whenever you need to handle a signal and reimplement the method to handle the signal. Instead of the string connection you get:

new QSignalHandler1<String>(ui.lineEdit.textChanged) {
public void handle(String s) {
System.out.println("Got the string: " + s);

In this case we use generics to match the types of the signal with the type of the signal handler. If the two have different signature you get a compile error and if you forget to add the String generics argument to the QSignalHandler you'll get a warning telling you its "unsafe" or something similar. The 1 at the end of the QSignalHandler is the number of arguments, similar to the one in QSignalEmitter.Signal. This is already in our 4.4 branch, but the code is trivial so if you want this right away, I'll give you a sample that you can "steal" and use.

package com.trolltech.extensions.signalhandler;

import com.trolltech.qt.*;

* Signal handlers are a convenience class that provides compile time type checking of signal / slot
* connections.
public abstract class QSignalHandler1<T> {

* Creates a new signal handler that sets up a connection from the input signal to this object.
* @param signal The signal to connect to.
public QSignalHandler1(QSignalEmitter.Signal1<T> signal) {
signal.connect(this, "handle(Object)");

* Reimplement this function to handle responses to the signal this handler is connected to..
* @param arg The Signal argument
public abstract void handle(T arg);

So as you can see, it is pretty straightforward. We move the string into the QSignalHandler class so that it is then checked, tested and verified once and for all and then all future use of QSignalHandler is checked. Because of the recurring generics type T we guarantee that the user uses the same type throughout the signal handler and its anonymous subclass.

If you have feedback on this API, please let us know...

Blog Topics: