What Is an Assert?
When a developer starts writing code, they will soon introduce if statements therein. An if statement is used whenever a certain condition needs to be tested. For example, one might write a pseudo-code if statement as follows:
In other words, if the water level goes over the high mark, an alert is raised. But maybe the water sensor is broken, so we update the code to match:
Great, now we will get an error and fail the routine if the sensor_readout is nonsensical. And only if the value proves to be sensical (due to the else clause—i.e., what to do in the opposite situation), proceed with checking the water_level against the high_water_mark.
However, maybe someone has turned the power off to the sensor. We can keep going like this for a while. We can cover every possible scenario imaginable and still miss a few. Sure, we could cover every possible situation with a matching else clause and verify that each condition is checked against another, but even in such cases, we might have missed some combinations of variables.
Even if we only had a limited set of variables to work with, the number of possible combinations a software package can find itself in is pretty numerous. And what’s more, these sorts of if conditional tests happen quite regularly in almost all software.
Reasoning a little further about this dilemma, we quickly understand that we (as developers) might (just like all humans make errors) sooner or later introduce code that lets the software run into undefined territory. Variable x is set to a specific value, variable y is assigned to another, and there was no provision for this in the code.
This is precisely the situation that an assert can, to some extent, provide for. An assert is another condition (Think about it like another if statement.) that asserts whether a given odd/uncommon/unplanned/unforeseen situation exists and usually handles such a situation by halting the program rather than continuing to run with an undefined/unknown state.
While the net that the asset test will cast is still limited to the smarts and skills of the developer who implements the assert, an assert can often be made broader than the limited confines of if statements testing the state of various variables, or it could be made quite specific to avoid certain dangerous situations.
For example, let’s say that our little water sensor is mounted in a rain tank. The water should, therefore, never be boiling. If our water sensor had a temperature meter, however, we could make sure, even though it would/should never happen. Let’s add an assert to the pseudo-code that we started above.
Instead of boiling point (100 degrees Celsius), we will check for a more reasonable maximum of 70 degrees Celsius, which should still never be reached when thinking about catching rainwater, at least, in our opinion. Remember the word “opinion,” as this becomes important when considering the smarts of the developer implementing the assert. (More on this below.)
We wrote the assert in reverse. The code needs to assert that the water temperature is less than 70 degrees Celsius. If it isn’t, it will execute the code block, which will raise an assert message, and then the software will fail and exit.
Asserts in actual code are quite similar to the example above. They test whether a given situation applies or not, and subsequently halt (or crash in a controlled way) the program/software at hand.
Often, these assets are logged to the application’s log files or even directly on the screen output. Reviewing them and/or searching for a copy of the exact assert message in your favorite search engine will often (if the bug was previously found) lead you to a bug report on the same.
Assert messages are often bugs, although they might simply be bugs in the developer’s reasoning. After all, who says that 1,000 years from now, the rain might not be hotter than 70 degrees Celsius? (Let’s hope not, though!)
An assert message is the output rendered by the assert introduced by developers into the code—i.e., the actual textual output generated by the software and as displayed on the screen or in the logs. For example, imagine this assert message being shown for the program above.
Although it looks a bit cryptic (as some assert messages are), looking a little closer makes us realize that in the second part, water_temp was exchanged by 88 and that the output is false (i.e., the assert water_temp < 70 failed as the water was 88 degrees, and thus, the assert triggered the assert message). Yes, it can get a little confusing.
Armed with these new skills, debugging an assert message the next time you see one becomes a lot easier. You might also find it easier to understand exactly what was going wrong at the time of the application halt.
What Is an Error?
Errors in computing happen all the time and for a wide variety of reasons. They happen both at the developer and the user level and at every step in between. For example, a DevOps engineer might forget to include a necessary file, or a package signer might use the wrong key to sign the software, and so on.
In short, a computer error can be defined as a problem with computer hardware or software. There are some examples of an error even in the limited pseudo-code above. When the sensor_readout == nonsensical condition is met, an error message is displayed.
There are certain errors that are more common than others. For example, using a wrong path or filename is a common error. Power-related issues (for example, battery low) are also quite common errors.
Errors are quite separate and different from assert messages, even though the assert message in itself can be viewed as an error, or rather, as an undefined situation now covered by the assert. In general, a computer error usually translates to “I need a human to fix this” quite well.
As computers get more intelligent and AI evolves, hopefully, fewer errors will be produced, although there is much room left for discussion and even arguments in that area.
What Is a Crash?
A computer crash can take many forms. We are all familiar with Microsoft Windows blue screens, which tended to happen when an application misbehaved or some core part of the operating system or the machine’s hardware would fail.
Most of the time, however, a crash is a software application that ran into an undefined situation. There are many such undefined scenarios possible. A computer might have tried to write to a RAM area already in use, thereby upsetting itself or another application, or maybe it ran into a scenario where it tried to divide by zero (which is impossible), or some similar situation.
Many operating systems will write a core dump file (if so configured), which allows a developer and, at times, an end-user who is somewhat skilled, to debug the issue at hand.
If you would like to learn more about debugging when things go wrong, including analyzing core dump files, you will likely find our Debugging with GDB: Getting Started article to be of interest.
A crash might also be the result of an application running into an undefined situation, which is not handled by an error (the lightest way for an application to inform you that something is amiss) or an assert (a deeper issue, originally excluded by the developer as impossible but still occurring).
Also, note that a program build for testing—i.e., with debugging information (including debug-level-only asserts) embedded in the end result binary—might crash when it produces an assert, as is the case, for example, with the MySQL server.
Wrapping up
In this article, we explored the concepts of assertions, errors, and crashes as well as how they relate. We took an in-depth look at what asserts might look like inside the code and how this relates to a real-life example of monitoring the water level and temperature with a water sensor. Next time you run into an assertion message, take a closer look, and enjoy debugging!