Open code review: Catch

This is one of the “open code review” posts, where I publish my notes after looking through and playing with one of the open source C++ projects. My main goal here is to become a better coder by learning from the experience of other developers, and my secondary goal is to build a mental map of the tools and frameworks available “out there” to not reinvent the proverbial wheel, should I ever need one. The blog post expresses my personal opinion, not affiliated, endorsed, sponsored, etc. I am not arguing for or against the usage of any specific open source library. I will be grateful if you take time to point out any misunderstanding I might have.

Today I looked at philsquared/Catch, “a multi-paradigm automated test framework for C++ and Objective-C (and, maybe, C)”.

Actually, it was long on my list of “to-read” projects, since the first time I’ve heard of it was at the “Meeting C++” conference in December ’14, where Phil Nash, its author, talked about it.

So, why bother about this “yet another” test framework? Catch dedicates a page to the answer, but here’s what caught my attention:

  • extreme simplicity and minimalism of the design (you need to learn very few things to start writing Catch tests);
  • plain text snippets as “first-class” citizens in test names and descriptions (so the tests look like a spec, and test assertions give richer description of the failed requirement);
  • an inventive way to get rid of setup code duplication via the mechanism of “sections” (saves you some coding, see below an example of how sections work).

Here’s how a trivial test in Catch looks like, from its tutorial:

  #define CATCH_CONFIG_MAIN  // This tells Catch to provide a main() - only do this in one cpp file
  #include "catch.hpp"

  unsigned int Factorial(unsigned int number) {
    return number <= 1 ? number : Factorial(number - 1)*number;
  }

  TEST_CASE("Factorials are computed", "[factorial]") {
    REQUIRE(Factorial(1) == 1);
    REQUIRE(Factorial(2) == 2);
    REQUIRE(Factorial(3) == 6);
    REQUIRE(Factorial(10) == 3628800);
  }

 

And here’s my somewhat unorthodox demo of Catch “sections”. I’m trying to illustrate the mechanism of the section tree traversal. This is not a test at all, I’m using Catch sections here to print 4 lines from Shakespeare which share some of their first few words starting with “Thou shalt…” :) For a more practical example see the vector tests in the Catch tutorial.

  #define CATCH_CONFIG_MAIN
  #include "catch.hpp"

  #include <iostream>
  #include <string>
  using namespace std;

  // Catch "sections" are "forks" in the test execution tree.
  // A test run traverses all possible paths to the leaves.
  // This test case produces 4 strings by traversing 4 paths. 
  TEST_CASE("4 lines from Shakespeare")
  {
    cout << "Thou shalt ";  // http://www.rhymezone.com/r/ss.cgi?q=thou+shalt
    
    SECTION("...not")
    {
      cout << "not ";
      
      SECTION("")
        cout << "stir a foot to seek a foe. (Romeo and Juliet: I, i)" << endl;
      
      SECTION("")
        cout << "sigh, nor hold thy stumps to heaven, (Titus Andronicus: III, ii)" << endl;
    }

    SECTION("")
      cout << "remain here, whether thou wilt or no. (A Midsummer Night's Dream: III, i)" << endl;
    
    SECTION("")
      cout << "continue two and forty hours, (Romeo and Juliet: IV, i)" << endl;
  }

  // Test output:

  //Thou shalt not stir a foot to seek a foe. (Romeo and Juliet: I, i)
  //Thou shalt not sigh, nor hold thy stumps to heaven, (Titus Andronicus: III, ii)
  //Thou shalt remain here, whether thou wilt or no. (A Midsummer Night's Dream: III, i)
  //Thou shalt continue two and forty hours, (Romeo and Juliet: IV, i)
  //===============================================================================
  //test cases: 1 | 1 passed
  //assertions: - none -

Read the rest of this entry »

C++ curiosities: std::move that doesn’t move

Despite its name, std::move doesn’t move anything. std::move is no more than a type cast. It has 2 major purposes in life: to return an “rvalue reference” to its argument and to mislead people into thinking it does more than that. In fact, you can call the bluff by calling static_cast<T&&> explicitly instead of std::move and observe all move operations still working to the same effect:

  #include <iostream>
  using namespace std;

  struct A 
  {
    A(){};
    A(A&&) { cout << "I'm so moved!" << endl; };
  };

  int main() 
  {
    A a;
    A aa(static_cast<A&&>(a)); // prints "I'm so moved!"
  }

Why does it matter? Because developers tend to forget about the fact, and treat calls to std::move as some kind of reset() method on the object, and that can lead to defects and fragile code.
Read the rest of this entry »

Open code review: g3log

This is one of the “open code review” posts, where I publish my notes after looking through and playing with one of the open source C++ projects. My main goal here is to become a better coder by learning from the experience of other developers, and my secondary goal is to build a mental map of the tools and frameworks available “out there” to not reinvent the proverbial wheel, should I ever need one. The blog post expresses my personal opinion, not affiliated, endorsed, sponsored, etc. I am not arguing for or against the usage of any specific open source library. I will be grateful if you take time to point out any misunderstanding I might have.

Today I looked into KjellKod/g3log, an asynchronous logger “with dynamic sinks”.

g3log was inspired by Google’s glog library, but, while it feels similar API-wise, it fixes a significant flaw in glog: namely, g3log is asynchronous. Log requests in g3log are put into a queue and flushed to disk by a background thread. This alone makes the library much more attractive than glog, in my opinion. Typically, people write in C++ because they want performance, and blocking disk IO calls in the middle of some intensive computation just do not feel right.

You can find more details about the logger and the sample usage on the project page or in Kjell’s blog. Here is a quick example, the syntax is quite straightforward:

LOG(INFO) << "streaming API is as easy as ABC or " << 123;
LOGF(WARNING, "Printf-style syntax is also %s", "available");

int less = 1;
int more = 2;
LOG_IF(INFO, (less < more)) << "If [true], then this text will be logged";
// or with printf-like syntax
LOGF_IF(INFO, (less < more), "if %d<%d then this text will be logged", less, more);

Read the rest of this entry »

Open code review: FlatBuffers

This is one of the “open code review” posts, where I publish my notes after looking through and playing with one of the open source C++ projects. My main goal here is to become a better coder by learning from the experience of other developers, and my secondary goal is to build a mental map of the tools and frameworks available “out there” to not reinvent the proverbial wheel, should I ever need one. The blog post expresses my personal opinion, not affiliated, endorsed, sponsored, etc. I am not arguing for or against the usage of any specific open source library. I will be grateful if you take time to point out any misunderstanding I might have.

Today I looked into google/flatbuffers, a “Memory Efficient Serialization Library”.

FlatBuffers is a member of a numerous family of serialization frameworks, being a lesser-known sibling of Google’s Protocol Buffers (FlatBuffers even understands some subset of their .proto language) and a distant relative of such libraries as Cap’n’Proto, Rapid JSON, pugixml and Thrift. I’m not going to compare them all here, and the optimal choice is likely to be problem-specific anyway.

FlatBuffers documentation is quite good in my opinion, it shows some benchmarks and highlights the specific features of the library. What FlatBuffers claims as its strength is the absence of the packing/unpacking step per se, e.g. instead of “deserializing” the data from the binary representation into a newly allocated struct you just get the fields of the struct mapped as offsets onto the underlying byte array. That’s why the benchmark page proudly demonstrates comparison with “raw structs” serialization performance. FlatBuffers uses a platform-agnostic language-independent binary format, always little-endian and with predefined alignment. The few poor souls with big-endian machines will pay for some extra binary swapping here.

The workflow of using FlatBuffers is 2-phased, just like with protobuf. In the first phase, you write an interface definition file, describing the structure of the payload you’d like to serialize. Having that description, you run the FlatBuffers code-generator to produce the reading/writing code in C++, Go, Java or C# (or in all of them). In the second phase, you use the generated code and some extra headers in your project to serialize/deserialize your data. Normally, you’d use the default binary serialization, as that is the most efficient approach, but the library also lets you serialize to/from JSON, if you so desire, e.g. for debugging purposes or to interact with a JavaScript API.

Here is how an interface definition file looks like, it’s really pretty straightforward, for more detailed explanations go to this page:

namespace MyGame;

attribute "priority";

enum Color : byte { Red = 1, Green, Blue }

struct Vec3 {
  x:float;
  y:float;
  z:float;
}

table Monster {
  pos:Vec3;
  mana:short = 150;
  hp:short = 100;
  name:string;
  friendly:bool = false (deprecated, priority: 1);
  inventory:[ubyte];
  color:Color = Blue;
}

root_type Monster;

Read the rest of this entry »

An inquiry into CPL values

Christopher Strachey and CPL are sometimes mentioned in the discussions of C++ value categories, though usually just briefly and for dubious reasons: C++ value categories are defined in a specific fashion different from Strachey’s blueprints, and some even say that the analogy is downright confusing. I’ve attempted to get a better understanding of the issue, and this post summarizes my findings.

“The terms “lvalue” and “rvalue” are deep in C++’s genes. They were introduced by Christopher Strachey for CPL [Strachey,196?], the ancestor to BCPL. Dennis Ritchie used “lvalue” to describe C (e.g. see [K&R,1978]), but left out “rvalue”, considering “lvalue” and “not lvalue” sufficient. I did the same for early definitions of C++ (e.g. see [Stroustrup,1986] and [Ellis,1989]). The terms “lvalue” and “rvalue” are “all over” the draft C++ standard. Clearly, this is not terminology to mess with without serious reason and great care.” — B. Stroustroup: “New” Value Terminology

“The terminology of “lvalues” and “rvalues” is confusing because their history is confusing.  (By the way, they’re just pronounced as “L values” and “R values”, although they’re written as single words.)  These concepts originally came from C, and then were elaborated upon by C++.  To save time, I’ll skip over their history, including why they’re called “lvalues” and “rvalues”, and I’ll go directly to how they work in C++98/03.  (Okay, it’s not a big secret: “L” stands for “left” and “R” stands for “right”.  But the concepts have evolved since the names were chosen, and the names aren’t very accurate anymore.  Instead of going through the whole history lesson, you can consider the names to be arbitrary like “up quark” and “down quark”, and you won’t lose anything.)

C++03 3.10/1 says: “Every expression is either an lvalue or an rvalue.”  It’s important to remember that lvalueness versus rvalueness is a property of expressions, not of objects.

Lvalues name objects that persist beyond a single expression.  For example, obj , *ptr ,ptr[index] , and ++x are all lvalues.

Rvalues are temporaries that evaporate at the end of the full-expression in which they live (“at the semicolon”).  For example, 1729 , x + y , std::string(“meow”) , and x++ are all rvalues.” — S.T. Lavavej “Rvalue References: C++0x Features in VC10, Part 2”

But why even bother reading about CPL and its concepts?

Well, at least for 2 reasons:

  • first, naturalistic: CPL has never been completely finished, but a compiler for a small subset of it (BCPL) focused on system programming was eventually implemented, then after a couple more mutations the language turned into C and then C++, so there is a direct relation between CPL and C++ in the evolutionary sense, and it’s interesting to trace the path of the inherited characteristics and, (maybe not so) surprisingly, discover that many modern C++ features are merely the newly “re-discovered” items from the Strachey’s ideal language “wish list” from the 60’s;
  • second, pragmatic: Strachey’s concepts of R-values and L-values, in my opinion, are simpler, more fundamental and more universal than “rvalues” and “lvalues” of C++, and they uncover some important semantics underlying expression evaluation in most programming languages (C++ included). From here on I’ll use terms R-value and L-value to refer to the concepts introduced in [Strachey, 1967], and terms rvalue, lvalue, prvalue, glvalue, xvalue as described in [Stroustrup, 2010].

Read the rest of this entry »