First of all, this post is not meant to criticize Qt in any way, just to raise some thinking points for people who create libraries.

After my talk at aKademy 2014, I’ve decided to start a short series of blog posts about some considerations to be had when designing public API and overall practices to make your code safer and cleaner.

API Design

When we are thinking about the API of a library we are crafting, we usually tend to think only about how easy it will be for the user to use it. And I’d say that Qt is doing very well in that regard.

The problem is that the API design should not be only about that.

When crafting code, we usually ballance between keeping it readable by others, making it execute as fast as you can, to use as less memory as posible etc.

API design should be the same. Although, in this case, you can give a greater priority to the readability, but not by completely sacrificing the other parts.

A small example

A nice example of this sacrifice can be seen when comparing QTextStream::readLine to std::getline.

// API shortened to look prettier
QString QTextStream::readLine();
std::istream& getline(std::istream &input,
                      std::string &line);

The Qt version looks much nicer - it reads a line, and returns it. It can not be any simpler.

The STL version, on the other hand, returns the (rest of the) stream after the line is read, and it returns the actual line through the out argument. Is there anyone who actually likes the out arguments?

The benefit of this is that you can do a if(std::getline(:::)) and get whether the stream is still valid, which is useful sometimes. But, still, it looks as a harder function to use than the one from QTextStream.

Things start to look a bit different once you start thinking about the most common use case for using a function that returns a line.

// taken out of the QTextStream documentation
QTextStream stream(:::);
QString line;
do {
    line = stream.readLine();
    // do something
} while (!line.isNull());

The equivalent code using the function from the STL would be something like this:

std::ifstream stream(:::);
std::string line;
while (std::getline(stream, line)) {
    // do something
}

After seing the examples, it is a little bit hard to mark the QTextStream::readLine as the clear winner when the ease-of-use is concerned.

Measuring the speed

But, the point of this post is not to talk about that.

The point is to show that the API design has influcence on the other aspects, and not only on readability. The nice API of Qt comes with a significant performance penalty.

I’ve just tested the previous code snippets on a text file that has somewhere around 56000 lines. Each line of the file was longer than 50 characters to exclude the possibility for the libraries to use the short-string optimizations.

The results were measured using the clock() function in the ctime header (start_clock = clock(); … clock() - start_clock), and the tests were repeated quite a few times:

* Qt code took ~41000 // QString
* Qt code took ~30500 // edit: QByteArray
* STL code took ~8700

The STL version is almost 5 times faster (edit: 3.5 times compared to QByteArray version).

And it is not because Qt’s implementation is slow or anything. It is mainly because of the API design.

Why is that?

I’ll write the answer below in the comments section to allow you to think about what could be the issue here.

edit: Added QIODevice/QByteArray to the above mix, as suggested by csslayer.