When you don’t trust Strings…

Published Friday September 28th, 2007
3 Comments on When you don’t trust Strings…
Posted in Qt Jambi

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…

Do you like this? Share it
Share on LinkedInGoogle+Share on FacebookTweet about this on Twitter

Posted in Qt Jambi

3 comments

Peter says:

What about adding static type checking to Qt/ C++.

This “no problem, we will see at runtime if all is correctly connected”
is maybe the ugliest point in the whole Qt design, here boost:signals
is much better.

(I ONLY talk about the static type checking, not about all the
other moc stuff which isn’t possible with boost::signal!)

wysota says:

Peter: but how would the compiler check a string? SIGNAL() and SLOT() macros make a const char* out of the signature, so the compiler sees it as a quote bounded string. It would have to be done on the macro level – the check would have to be done during expansion of the macro and the macro processor knows nothing about C++ syntax (not speaking about Qt classes).

Scavenger says:

Adding the static type checking to Qt/C++ connection will be great. In most times types of the signal and slots are known at compile-time. As far as I undertand the most complex thing is making string from the known type. It may be that signals and slots can be connected via pointer-to-memeber functions alongside of string definitions. Low-level implementation could be provided in QMetaObject (as it exists for the strings now) and supported by template method(s) in QObject.

Wysota: Expansion of macros to const char * is not the only possibile expansion. πŸ˜‰

Commenting closed.

Get started today with Qt Download now