Status update November 2019

For the past month I’ve been primarily working on Cute Chess, a GUI, a command-line interface and a library for playing chess.

Last month I created my first QL queries for searching for potential issues in the Cute Chess codebase. I integrated these queries to Cute Chess so that they’re run for every Github pull request. The plain QL queries I wrote last month required additional metadata to be added. The metadata section is well documented.

Here’s an example how I see myself writing future QL queries. Alwey, the most active contributor to the Cute Chess project, had spotted a problem some time ago in Game Settings. Here’s the diff he submitted that fixes the issue:

diff --git a/projects/gui/src/gamesettingswidget.cpp b/projects/gui/src/gamesettingswidget.cpp
index ff823a55..e4640b56 100644
--- a/projects/gui/src/gamesettingswidget.cpp
+++ b/projects/gui/src/gamesettingswidget.cpp
@@ -161,7 +161,7 @@ OpeningSuite GameSettingsWidget::openingSuite() const
                return nullptr;

        OpeningSuite::Format format = OpeningSuite::PgnFormat;
-       if (file.endsWith(".epd"), Qt::CaseInsensitive)
+       if (file.endsWith(".epd", Qt::CaseInsensitive))
                format = OpeningSuite::EpdFormat;

        OpeningSuite::Order order = OpeningSuite::SequentialOrder;

Note how the braces are written which results in the controlling expression inside the if statement to be evaluated as a comma expression. The result of the evaluation is 0, since Qt::CaseInsensitive is a constant with 0 value. Thus, the controlling expression is always false.

While using a comma expression in a if statement is a valid use case, I was almost certain that Cute Chess does not use such construct. I verified this from the LGTM query console and indeed, this was the only instance of such expression in a if statement. To prevent similar errors happening in the future, I created a QL query that will flag uses of comma expression in an if statements as potential errors.

Finally, I started the work to switch our internal implementation of JSON parsing and serialization to QJson — the JSON library inside Qt. In Cute Chess, chess engine configurations are stored in JSON format. When the decision to use JSON was made, there was no native way to process JSON files in Qt, thus our own implementation was born. Our implementation is packaged separately in the source tree, has extensive tests and has been used in Cute Chess for years. In other words, there’s nothing wrong with it.

With that said, I was curious to see how difficult it would be to change the implementation to the native Qt one and whether there would be any advantages in doing so. Internally, the serialization and deserialization is one using QVariants. In short, each engine configuration is represented as QVariantMap (key-QVariant pairs) and fed to the serializer. This glue code was easy to port to QJson.

The differences in error reporting between our implementation and QJson were surprising. Ideally, we would like to report as clear error messages as possible so that if someone incorrectly edits the configuration by hand, they have clear indication what error is and where it’s located.

Here’s an example of a engine configuration file:

    "command": "./sloppy",
    "name": "sloppy",
    "options": [
          "alias": "",
          "default": 32,
          "max": 2147483646,
          "min": 0,
          "name": "memory",
          "type": "spin",
          "value": 32
    "protocol": "xboard",
    "stderrFile": "",
    "workingDirectory": "/Users/artoj/projects/sloppy/src"

If I remove the comma at the end from line 8, this what information the parsers report:

I much prefer our current implementation: it’s much clearer what is syntactically incorrect and where the error was encountered. I’m also confused why QJsonParseError does not report the line where the error was encountered — the parser has this information already. I’m currently leaning towards keeping our implementation.

I’ll conclude this month’s update with a simple Vim tip. If you’re using :find as a primary method of searching for files like I do, you can use :sf <filename> to create a horizontal split with the given file name and :vert sf <filename> for vertical split.