Posts

Initializations in if

One of the capabilities added in C++17 was using initializations in if/else statements: if (auto foo = f(); foo.isValid()) ... The primary use of this is to restrict the scope of the variables (which can include scoping variables like lock guards). However, it also provides for some slightly neater and better self-documenting code. There's a fundamental difference between Foo f = func(); if (!f.isNull()) {     doSomething(f); } else {     f = func2();     doSomethingElse(f); } //Use f more generally And the same block where f is not used again: the example above is a creation pattern with side effects.   It could be rewritten as std::pair<Foo, bool> MakeFoo() { if (Foo f = func(); !f.isNull()) {     return std::make_pair(f, true); } else {     return std::make_pair(func2(), false); } } ... auto [f, flag] = MakeFoo(); if (flag)     doSomething(f); else     doSomethingElse(f); ... where the creation logi...

Iterable Messages

I have been messing around with parsing and building delimited-field messages, using the FIX protocol's basic structure (key=value for fields, single-character field separator) as a simple model to work with. This is mainly to see what effect the new C++ features (notably the use of string views) have on performance. I have three classes with essentially the same logical interface. The first is a map of string views which owns the string on which the views are based. It allows access to the fields by key, and can be iterated over, but it is designed to be otherwise as cheap as possible. No ordering is done on the keys: so good for lookups, not good for generation unless the generating logic imposes an order or unless order does not matter. (In the FIX header order does matter, but in the FIX body it is not, strictly, important, although most implementations use a conventional numeric order.) Its projected use would be as an interim step on receiving a message: parse the string,...

Money

Back at the beginning of my professional development career I moved into a department where the main project had stalled for several months.  It was an application to allow timesheets to be submitted electronically, and the previous developer was failing to get bugs out of the application. It took me ten minutes of looking at it to ask "why is this using floating point"? The errors the developer couldn't manage were rounding errors, and the use of floating point pretty well automatically ensured that there would be cumulative and serious rounding effects. It took about a week to convert everything over to a fixed-point model, partly because this was pure C.  It took another week to convert what had been written as an iterative command-line utility reading and writing from the console into an application using curses to display interim results and provide rather better user feedback.  But the core problem had been the use of floating point. I have been amazed, since that d...

Loops

This is where my bias for a certain sort of descriptive programming as essential to maintainability comes out. By "descriptive" in this context I mean "code which is explicit about what the intent of the developer is". (A side effect of this sort of declaration is usually small, named functions, which are good for other reasons. But this post isn't about functions, as such. It's about loops.) The for loop was introduced as part of the structured programming revolution. (It's not a fundamental: it's easy to create with goto, the minus operator, and if, the real primitives*, but it "tames" the goto into a reliable and meaningful higher-level concept.) * Ok, jz, jnz, add, sub, and cmp are the real primitives. I'm not talking assembler here. The classic C for loop is int i; ... for (i = 0; i < lim; ++i) { contents, possibly referencing i } Recent languages have provided syntactic sugar when iterating over something other than pure integ...