Category: Blog

Assert? Yes, but actually No

Everywhere I worked, assertion caused mixed feelings. On one side, they are a valuable tool to … well, assert that required conditions are respected; on the other side, they may crash your running program, spoiling the fun.

There are many ways to mitigate the problem and guidelines to make this tool more effective, but in the end, you have to decide whether you want assertions checked in your release build or ignored.

Why do assertions cause the execution to stop? The rationale is that when an assertion fails, a bug has manifested and the software’s behavior is wrong. Better stop than wrong.

The first rule to follow is to use assert for contract enforcement, not for error checking. If you are reading data from a serial line, you should expect spurious or unwanted characters to come down to your software. You do error checking, discarding or recovering data; you never assert there.

Also, the standard implementation may not be the best one for your needs. Usually, I define my own assert that, when running in the debugger, halts execution if it fails. Also, my custom assert for firmware and embedded software tries to save flash space by just reporting the address of the assertion (then the good programmer looks up in the listing file to see what went wrong).

I tend to agree that a failed assertion should stop (or restart) the application. Indeed, if a precondition or an invariant is not fulfilled, anything could have happened, and you may get crashes in unrelated operations, no crashes but wrong results, and security exploits. One possible outcome could even be the right behavior, but it is like sorting a sequence with bogosort.

If you prefer the application to be Terminator-like and keep going, you have a couple of options. You could log the fail, possibly with a full stack trace, so that the future you can be able to debug. Another option is to throw an exception and let the catcher decide what to do. This can be valuable in an application that performs several operations: an operation fails, but other operations may keep succeeding. Lastly, you can disable assertion checking, and this is possibly the worst thing you can do.

Pondering assertions lately brought me to the following conclusion – programming by contract is flawed. It is good to define a contract under which your code properly works, but it is bad that you can only detect that the contract has been breached after it has been breached. The contract is discovered to be void at the worst time possible – runtime. The whole point of having compiled code (syntax, type, and semantic checking done ahead of execution time) is thwarted by a failed assertion.

Wouldn’t it be good if we could prove the code won’t breach the contract at compile time?

Well, actually this is possible to an extent, and the language gives us a hint on how to do it. If a function accepts a std::string, you do not need to assert that you actually got a std::string. This is because no one could call that function with, say, an int and get the code to compile.

// contract: I want a std::string.
void doSomething( std::string const& s );
void somewhereElse()
{
  doSomething( 3 ); // compile time error, the contract is breached
}

So the key is in leveraging types to define contracts. Let’s consider a fictional code, where you want a function to accept an even number. The trick is to define a class that encapsulates an integer and can be constructed only from even numbers:

(Note, C++ got all the defaults wrong, requiring decorating classes with an unbelievably verbose boilerplate of constexpr, noexcept, [[nodiscard]] and the like. For the sake of clarity, I’ll leave out all those, but they are required in production code)

class EvenNumber {
  private:
    int mValue;
    explicit EvenNumber( int value ) : mValue{ value } {}

  public:
    int getValue() const { return mValue; }

    static std::optional<EvenNumber> makeEvenNumber( int n ) {
      return n % 2 == 0 ? EvenNumber{ n } : {};
    }
};

To build only an even number, I made the constructor private and provided a factory method that returns an optional of EvenNumber. If you try to build EvenNumber with an even number, you get an optional with a value; otherwise you’ll get an empty optional.

This is indeed no magic; instead of checking where the value is used, I need to check where the value is produced. But this is convenient from several points of view:

  • The value is produced once, but possibly used several times – the cost of checking is lower;
  • At the usage location, I likely don’t know how to handle an invalid value, resorting to assert or throwing an exception. Being aware of the contract breach where the value is produced is likely to give us more options on how to deal with it, like… better safe than sorry.
  • No invalid data exists in the program; if data exists, then it is valid by design.

Regretfully std::optional is a bit broken, so you may still get an UB if you try to dereference an empty optional. But this can be addressed either by using monadic optional (such as ChefFun::Option), or by adopting stricter guidelines on checking std::optional where they are produced and avoiding using them to pass values around.

Wrapping integers and strings into Smart types (or refined types) is not that hard; some template metaprogramming may even come to help to deal with common cases.

Also, enum classes may be used to prevent misuse. A common case in firmware is the handling of the flash memory, which can be organized into segments. So a memory location is identified by a segment and an offset within the segment. Let’s say that you provide a function to read a memory location:

std::byte readFlash( uint32_t segment, uint32_t offset );

This is error-prone because nothing prevents the caller from messing up the segment and offset. Using enum classes, you can write:

enum class Segment : uint32_t {};

enum class Offset: uint32_t {};

std::byte readFlash( Segment segment, Offset offset );

The compiler won’t let you pass any integer to the arguments; you have to cast them into their types, making it impossible to swap them.

This is a contract that cannot be enforced by assertion since there is no way to tell what an uint32_t is in the intention of the programmer, not at run time (nor at compile time).

Back to what can be enforced by assertion, what about null pointers?

Can we enforce that a pointer be non-null by type? What a huge advance – we would get rid of tons of defensive code checking for pointer validity and possibly prevent some crashes.

Before proceeding, there is a non-null pointer type concept in GSL. This type prevents you from constructing a pointer from a literal nullptr, but doesn’t prevent you from assigning a nullptr:

gsl::non_null_ptr<T> p0{0}; // compile time error

T* p1 = nullptr;

gsl::non_null_ptr<T> p2{ p1 }; // ok

And if you try to dereference a gsl::non_null_ptr<T> that is a nullptr, you’ll get the program terminated (exactly as if an assertion would have been violated).

This shows another shortcoming – how many times do you initialize a pointer with a literal (besides nullptr for marking empty values)?

But we can do better; we can write our template with a factory method that constructs only non-null pointers, avoiding random termination on pointer dereferencing.

template<typename T>
class Ptr<T>
{
  private:
    T* mPtr;
    Ptr( T* ptr ) : mPtr{ptr} {}

  public:
    static std::optional<Ptr<T>> makePtr( T* p ) {
      return p != nullptr ? Ptr(p) : {};
    }
};

This template core looks promising – everything can be computed at compile time, and there is no overhead in copying and assigning.

As often happens, the devil is in the details. We want to be able to use it as a language native pointer. This means:

  • dereference the pointer (operator*, operator->);
  • use Ptr<T> where T* is expected (implicit conversion);
  • support const-correctness;
  • perform pointer arithmetic;
  • compare with other Ptr<T> or T*;

That’s a whole lot of features. Some of them are trivially implemented. Some are less trivial. For example, adding or subtracting an integer to a pointer gives you a pointer. Since you need to be sure that the pointer obtained in this way is valid, you cannot return Ptr<T>, but you have to wrap it in a std::optional:

std::optional<Ptr<T>> operator+( intptr_t offset ) const;

+= and -= are better avoided since their semantics may not be clear for edge cases:

char c = ‘x’;
Ptr<char> pc = Ptr<char>::make( &c ).value(); // here is ok, since &c is not nullptr for sure
intptr_t w = reinterpret_cast<intptr_t>(pc.get()); // w has the same value of c;
pc -= w;

What is the value of pc? Surely it cannot be nullptr. The operation just failed… silently?

For a complete implementation, you may look into the ChefType repository.

Back to our intent – we can use type safety as a compile-time alternative to assertions. Is this always the case?

Consider a timer object, it has three states: created, armed, and expired. The first transition from created to armed is under code control, while the transition from armed to expired is triggered by something outside our code. Now consider the following assertion –

void cancel( Timer&amp; t )
{
  assert( t.isArmed() );
  // ...
}

Is there a way to encode this assertion using types? Actually, no, because there is no way to change the type of the object to reflect its state. You can do it for the first transition:

class CreatedTimer;
class ArmedTimer;

void f()
{
  CreatedTimer ct{};
  // ...
  auto at = armTimer( ct, TIMEOUT );
  // ...
}

This is fine, and it is also useful – for example, the ArmedTimer class may expose a wait() function that is not provided by the CreatedTimer, preventing you from waiting on an unarmed timer.

However, the change from Armed to Expired is not under compile-time control since it depends on an asynchronous event occurring at run-time.

On the other hand, maybe we can code the timer with some defensive coding that also behaves when the state is not the required one.

I mean, when we get characters from an input, we would like to have only a valid sequence. How good! We could avoid checking for wrong inputs and avoid coding error messages. But we know that inputs can be anything, and we need to validate, accept what is acceptable, ignore what is ignorable, and recover in the other cases.

The same approach could be pursued for the timer – after all, triggering is an external event that may happen at any time. Even if we require that the timer is not expired, it may expire a split second after the check.

Design Principles and Where to Find Them

In the past two years, I interviewed several candidates for embedded software roles. Regardless of the skill and experience level of the candidate, one question I asked was about Design Principles. Something like “Could you tell me about one Design Principle?”, very open, but the idea is to start talking about design principles, not checking the candidate knows a specific one in detail.

What struck me is that in two years, none of the candidates knew about Design Principles. Someone candidly and transparently answered that they don’t know; someone else started talking about design patterns; someone also glanced over the question. But not a single candidate could answer, not even those fresh from Software Engineering degrees.

Continue reading “Design Principles and Where to Find Them”

One, two, many FSMs!

Once upon a time, I thought the world needed me to explain how to properly design and implement a state machine, preferably in C++. After jotting down a few ideas, I planned to write two articles. As luck would have it embeddedrelated was looking for authors at the time. So I decided to publish with them instead of on my blog.

Continue reading “One, two, many FSMs!”

Lambda World 2025

As promised last year in Cadiz by the Yay Yay people, Lambda World returned for a 2025 edition. Going to Cadiz is a sort of pilgrimage in itself – wake up at an ungodly time in the night, no direct flight, endless wait in airports, train, and eventually some vigorous walk on the cobblestone alleys in the old town. Once at the conference, pilgrims listen to the words of FP gods… or something like that. Totally worth it, but after a journey like this, you may well have mystical visions.

Continue reading “Lambda World 2025”

What are we missing? Part 2

It took quite a while to edit the second part, but I hope it is worth the wait.

Optional Semicolons

Once upon a time, BASIC didn’t need any instruction termination symbol. If you wanted to stick two or more instructions on the same line, you had to separate them with a colon (yes, this was before semicolons). Then it was Pascal and C, and the termination/separation character made its appearance (well, maybe history didn’t unfold exactly like this, but this is, more or less, how my relationship with the instruction termination evolved).

Scala, Python, and other languages do not need semicolons or make their use optional in most contexts. This isn’t a great save, but it indeed makes me wonder why we need semicolons in C++; isn’t the “missing semicolon” one of the most frequent syntax errors? And if the compiler can tell that a semicolon is missing, couldn’t the compiler put it there for me?

Well, I guess the problem is backward compatibility. The semicolon-free parser would give a different meaning to existing code. Consider, for example, expressions that are split over multiple lines. In C++, it is ok to evaluate an expression and throw the result away. So, introducing a new statement separation syntax would be a mess – code that used to work may now present subtle problems hard to spot in debugging and code reviews.

Nonetheless, coding without semicolons is somewhat liberating, and remembering to put that character at the end of lines is a custom that I need a while to get back to when switching from Scala to C++.

Garbage collection

C++ has a strange relationship with garbage collection. This may come as a surprise to many, but in the first C++ book, The C++ Programming Language, Stroustrup wrote that C++ could optionally support garbage collection. Microsoft, in the early years of .NET, introduced a C++ extension (managed C++, then C++/CLI) to handle managed pointers – a different class of pointers for garbage-collected objects.

C++ had even a minimal support for GC, leveraged by some libraries such as the Boehm-Demers-Weiser. So, C++ is not a stranger to garbage collection, but this automatic way of deallocating objects has never caught on. In C++23, the minimal GC support was abruptly removed.

The common way for modern C++ to manage memory is via automatic objects and smart pointers. Automatic objects are allocated on the stack, and they are automatically destroyed when the execution leaves the scope where they were allocated. Smart pointers are defined by the standard library, and they provide reference-counting pointers that will automatically dispose of the pointed object when it is no longer used. By properly using std::unique_ptr and std::shared_ptr, memory management headaches are mostly gone.

Many languages went the other way, having garbage-collected objects as the default way to handle memory, with an optional way to allocate and manually free a bunch of memory.

So, what are the advantages of garbage collection? Well, there are three main advantages:

  1. no reference counting management penalty (paid each time you copy/assign a shared pointer around);
  2. thread safety (starting from C++20, there is a std::atomic partial specialization for std::shared_ptr (std::atomic<std::shared_ptr<T>>) that can be used, but – of course – you would pay an extra time for reference count update)
  3. GC works fine with reference loops – such as circular lists – while reference counting has troubles with these data structures.

Garbage collection lets the object exist with no additional space overhead, and the time overhead is incurred periodically during a memory scan that finds unused references and disposes unreferenced objects.

There are two main problems with GC:

  1. Periodic execution of the collector may degrade application performance. GC indeed made huge advances in this area; still, for real-time applications, it may be an issue to keep under control.
  2. Object disposal happens after the object’s last use, but you don’t control when. C++’s predictable destruction time allows C++ programmers to implement the RAII idiom.

So there are pro and cons, what I like about GC is that you don’t have to care about dynamic memory – in C++ I have to think whether the object is referenced only here (unique_ptr) or may be accessed by several parts of the code (shared_ptr), and then maybe I have naked pointers around I should take care of, and maybe I have to transform a smart pointer into another. As you can see, it is not as straightforward to allocate the object and let the GC do the work.

Lazy Values

This one is a bit unusual for the C++ programmer, but it definitely makes sense. Consider a variable with an expensive initialization:

class Foo
{
  val bar = f()
}

In this code, the call to f() happens each time an instance of Foo is created. Now, suppose that according to the execution context, the bar variable is never used. That’s a pity; the code is unnecessarily performing computationally heavy tasks.

The lazy attribute can be used like this:

class Foo
{
  lazy val bar = f()
}

And means that the function f() will be called at the first reference of the variable bar. Should we want to rewrite this in C++, it would be something like:

class TheTypeIWantJustOneInstance {
  T getBar() const {
    if( bar == std::nullopt ) {
      bar = f();
    }
    return *bar;
  }
  mutable std::optional<T> bar = std::nullopt;
};

Ugly and not very readable, the mutable specifier is really the flashing warning sign that something bad is ongoing.

The lazy tool is also useful for creating infinite data structures or processing a subset of a large amount of data without the need to compute or retrieve all the data of the superset.

Of course, there’s more to make this work properly in a multithreaded environment, with shared resources and order initialization defined by access. The only “undefined behaviour” is with recursive initialization (i.e., to initialize a, you need b. But to initialize b, you need a).

Object

The C++ language has no native notion of Singleton, so they are typically implemented as:

class TheTypeIWantJustOneInstance {
  public:
    static TheTypeIWantJustOneInstance& get() {
      static TheTypeIWantJustOneInstance instance;
      return instance;
    }
    ...
};

This may not be very thread safe since if the method get() is concurrently called by two threads, you could get instance initialized twice (at the same address… not good). But even if the thread-safety problem is addressed or avoided, the reader still has to decode a pattern of code to identify this as a singleton.

Scala offers the singleton construct natively. It is called “object”, and it looks like this –

object InstanceOfTheTypeIWantJustOneInstance {
  ...
}

The object construct offers a different perspective on class data. In C++, you can define a member variable or a member function to be static so that it is shared among all the instances of a class. In Scala, there is no such concept, but you can use the companion object idiom.

A companion object is an object that has the same name as an existing class. Methods and variables of the class have no special access to the companion object – they still need to import the symbols to access them. But from the user’s point of view, you can use the Class.member notation to access a member of the companion object. This gives quite a precise feeling of accessing something that is related to the class and not to the instance.

This example is from my solutions to the Advent of Code:

object Range {
  final val Universe = Range( 1, 4000 )
}


case class Range( start: Int, count: Int ) {
  def end = start+count
  def lastValue = end-1

  //...
  def complement : List[Range] =
    import Range.Universe
    assert( start >= Universe.start )
    assert( end < Universe.end )
    val firstStart = Universe.start
    val firstCount = start-Universe.start
    val secondStart = end
    val secondCount = Universe.end-end
    List( Range( firstStart, firstCount), Range(secondStart, secondCount ))
      .filter( _.isNonEmpty )

}

In this example, the class Range defines a numerical range (first value, count). The companion object contains a constant (Universe). The complement operation needs to access the Universe to compute the complement of a range. As you can see, to use the Universe symbol, the Universe class needs to import it.

Another interesting application is to use the companion object to provide additional constructors for the class. Using the apply method (that works like C++ operator()), you can create a factory:

object SimpleGrid
{
  def apply[A: ClassTag]( width: Int, height: Int, emptyValue: A ) : SimpleGrid[A] =
    val theGrid: Array[Array[A]] = Array.ofDim[A](height, width)
    theGrid.indices.foreach(
      y => theGrid(y).indices.foreach(
        x => theGrid(y)(x) = emptyValue
      )
    )
    new SimpleGrid(theGrid)

  def apply[A: ClassTag]( data: List[String], convert: Char => A ) : SimpleGrid[A] =
    val theGrid: Array[Array[A]] = Array.ofDim[A](data.length, data.head.length)
    data.indices.foreach(
      y => data(y).indices.foreach(
        x => theGrid(y)(x) = convert(data(y)(x))
      )
    )
    new SimpleGrid(theGrid)
}

Here, the companion object for the SimpleGrid class provides two alternate constructors. The first accepts grid width and height, and the default content for a cell. The second constructor accepts a list (of lists) and a function to convert the content of the list into cell initialization.

I find this approach interesting because it provides a native singleton concept and, at the same time, simplifies the class construct, removing the burden of class methods and fields.

Conclusions

In this post, we have explored several key concepts and constructs that distinguish C++ and Scala. Some are just syntactic sugar, like lazy vals and objects. You can argue that you can define your CRTC to implement them in a C++ library, but having them in the language sets the standard way for using these constructs, defines the dictionary if you want.

Other concepts are more drastically different – the memory management (alongside the principle that everything structured is accessed by reference) being the most evident. I am not a big fan of GC having delved more than once in optimizing memory usage to avoid that garbage collection spoiling the game (literally game). But aside from the point of relieving the programmer from low-level memory management care, garbage collection allows for better handling of objects.

In the next installment, we’ll go into the more advanced functional direction.

What are we missing? Part 1

I remember when I was (really) young, the excitement of the discovery when learning a programming language. It was BASIC first. That amazing feeling of being able to instruct a machine to execute your instructions and produce a visible result! Then came the mysterious Z80 assembly, with the incredible power of speed at the cost of long, tedious hours of hand-writing machine codes and the void sensation when the program just crashed with nothing but your brain to debug it.

A few years later, I was introduced to C. A shiny new world, where the promise of speed paired up with the ease of use (well, compared to hand-written assembly, it was easy indeed). And later on, C++. Up to this point, it seemed like a positive progression; each step had definitive advantages over the previous one, no regret or hesitation in jumping onto the new cart.

Continue reading “What are we missing? Part 1”

Professional Programmer

And the next discussion topic was “Are you programmer professionals? And what does it mean?”

What promised to be a C++ meet-up about topics that could spark a flame war turned into a thought-provoking moment.

It started lightly with the east-const vs west-const question (obviously east-const is the right answer), then things got much more foundational.

Continue reading “Professional Programmer”

Elf and Guards – Days 5 and 6

It couldn’t last forever—spending consecutive days writing about my progress in the Advent of Code took too much time and the rest of my life knocked on the door. In this post, I will try to update you quickly on days five and six.

On day 5 we had to assist an unfortunate handbook printer to get the updated pages in the correct order. Being magic-elven stuff, the proper order is not the natural increasing order of integers, but a custom order defined by number pairs – e.g. 43|12 means that page 43 has to be followed immediately by page 12. But stuff is not that simple, the order relationship is not linear like abc, but may branch, so to give you an idea, after a may come either b or d and then are both followed by c.

Continue reading “Elf and Guards – Days 5 and 6”

Finding XMAS – Day 4

Day 4 of the Advent of Code presents you with two new puzzles based on the word search puzzle idea. For some reason, you are teleported to the Ceres Elven Station (that made an appearance in AoC 2019), but there’s nothing for you to see here (yet) – not even the chief historian we looking for. So a small elf asks for your help to solve her word search.

Being Xmas elves the word you have to look for is “XMAS”, it can be written straight or reverse and can be written in any direction left, up left, up, up right, right down right, down and down left.

Continue reading “Finding XMAS – Day 4”

Elves’ Programming Language – Day 3

There are plenty of programming languages and, of course, Xmas elves have their own. Although your main goal is still to find the Chief Historian, we are now in a warehouse, historian minions are wandering around looking for their boss and we are tasked to fix the computer1.

This puzzle seemed a bit easier than the first two days, but I found it somewhat underspecified. You have to scan a text for patterns like “mul(n,m)” with n and m integers. For each pattern multiply n by m and sum all the products together.

Continue reading “Elves’ Programming Language – Day 3”