Working the Bash Shell Like a Pro, Service Pack 1

“Man is a tool-using animal. Without tools he is nothing, with tools he is all.”
— Thomas Carlyle

“A fool with a tool is still a fool.”
— anonymous

“A fool with a tool is a dangerous fool.”
— anonymous

Five years ago, I wrote a popular post called “Working the Bash Shell Like a Pro“, a short collection of essential tips and tricks for working efficiently with the Bash shell.

Like everyone, during my daily interaction with Bash I use many “tricks”, however, only few of them qualify for being added to my original list. Now, the time has come for a small update.

1. The Bash Curse

As you already know from the previous post, ‘!#’ selects the “entire command-line typed so far”, ‘:1’ takes the first argument in the “command-line typed so far” and ‘:r’ strips the extension from it. So changing the file extension of a file can be done with a fairly short command-line:

which is — depending on the path length — a lot shorter than

Instead of picking the first argument by employing the ‘:1’ word designator you could equally well take the last argument by specifying ‘:$’. Why? There is only one argument typed so far (“some/long/path/to/file.c”), so the first argument is the last argument. Consequently, this achieves the same effect as the previous command:

You probably think that this hasn’t gained us much since the number of characters to type hasn’t changed. That’s true but Bash has a special shortcut for ‘!#:$’ which is ‘!#$’. This saves us the colon and hence one character:

Since ‘!#$’ looks like a grawlix, I call this character sequence the “Bash curse”. I often use it many times a day, whenever I need to reuse (parts) of the argument preceding the argument I’m currently typing.

2. Skipping History

All of the mentioned tricks depend heavily on Bash’s history feature. After all, we want to save time by reusing something we typed earlier. Sometimes, however, we would rather not mess up our history. Take this command-line, for example:

Let’s further assume that you need to execute this regularly, many times a day. If you haven’t created an alias for it, you’ll probably pull the CTRL-R stunt*, something which I also explained in my previous post. So you hit CTRL-R and start typing “conan install”. Immediately, the desired command-line shows up and all you have to do is hit “Enter” to execute it.

So far so good. Sometimes, however, you want to fine-tune the command-line, for instance, to do a release build:

After you executed this command, your next attempt to retrieve the original command-line via CTRL-R will first find the one containing ‘-s build_type=Release’ which is not what you want as you only rarely want to do release builds. So it would have been better if the release build command-line had never been recorded in Bash’s history.

Another example of when you don’t want something to be entered in you Bash history is when you provide passwords/credentials on the command-line, as in

So how do you avoid that something is remembered in Bash? It’s easy. Just put a single space before the command you are about to execute:

This concludes service pack 1. Don’t expect service pack 2 anytime soon…

*) If I had to give up all the Bash tricks and only keep one, I’d would keep — hands down — the CTRL-R trick [back]

Why I Still Use std::lock_guard

“Better a lively old epigram than a deadly new one”
— Helen Rowland

If you’re programming in C++17 or above, you can choose among three different RAII-like mutex wrappers: std::lock_guard, std::scoped_lock, and std::unique_lock. But which one should you pick?

Most C++ programmers today advise you to use std::scoped_lock by default, unless you have to use std::unique_lock (if you want to move locks or if an API (like std::condition_variable) forces you to do so). One answer on StackOverflow goes as far as saying that

“… scoped_lock is a strictly superior version of lock_guard that locks an arbitrary number of mutexes all at once (using the same deadlock-avoidance algorithm as std::lock). In new code, you should only ever use scoped_lock.”

Despite of such advice, good ‘ol std::lock_guard is still my go to mutex wrapper. Why? Because most of the time, I

– only need to lock a single lock at a time
– don’t need to move or swap locks
– rarely need to manually lock/unlock the mutex once it’s wrapped
– prefer using features from earlier C++ standards, provided they fulfill my needs
– avoid code that violates Scott Meyers’ “most important design guideline”

Let me elaborate on the last point. Consider this code

This code looks like a typical case for a RAII-wrapper: You want to automatically lock and unlock (even if an exception is thrown, for instance) and reduce the time the lock is held to a minimum — hence the extra curly braces. Code like this gets written. I wrote code like this myself. I also saw similar code when reviewing somebody else’s code.

The problem with this code, however, is that it’s dead wrong. In the heat of the moment, the poor programmer forgot to pass a mutex to the std::scope_lock’s constructor, as in

In the original code sample, nothing is locked. Since the variadic constructor can be called without providing arguments, the compiler is happy. The application might actually work for quiet some time until it suddenly produces “strange results”. Try this with std::lock_guard and the compiler will rightfully reject your code, as std::lock_guard doesn’t have a default constructor.

In my view, the fact that std::scoped_lock’s constructor can be called without arguments is a gross violation of Scott Meyers’ “most important design guideline”, a guideline that I already wrote about recently: “Make interfaces easy to use correctly and hard to use incorrectly”.

To Pluralize, Or Not To Pluralize, That Is The Question

“Consciousness is a singular for which there is no plural”
— Erwin Schrödinger

When it comes to naming directories and files, some folks seem to insist on adding plural ‘s’ letters, as in

docs/, tests/, srcs/, recipes.txt

People like this have a collection-oriented view of the world. To them, “docs” is a label for a folder holding documents, just like a label on a box saying “screws” denotes that there’s a collection of screws in it.

When “pluralists” come across a directory named “doc”, it causes them grief. Why do people do that, they whine, there’s clearly an ‘s’ missing — is it just a typo or was it done deliberately, to save typing?

Let me tell you this: it’s usually done deliberately, but not to save a measly character. It’s done by individuals who have an identity-oriented view of the world and don’t care about containment and multiplicity. To such people, a folder named “doc” is the documentation of a project. It may hold a single text file, multiple PDFs and even some markdown documents. Likewise, “src” is the “source code” and “test” is the corresponding test in its entirety.

So there you have it: the reason why there is no ‘s’ in a name is just a coincidence in cases where the abbreviated name of what something is looks like the singular form of an item of a collection. “doc”, mind you, is not the abbreviation of “document” — it’s meant to be the abbreviation of “documentation”. (Incidentally, the Linux project avoids this confusion by keeping all the documentation in a folder named “Documentation“.)

My general advice is to strive hard to name something after what it is for the sake of better abstraction. Clearly, “essay” is more meaningful than “characters” and by the same token, I prefer “cookbook.txt” over “recipes.txt”. Only when a container has no higher-level purpose other than containment it should be given the plural form of items it contains, but this should rarely be the case.

A Small Matter Of Interface Design, Redux

“Bad design is simply great imagination without wisdom”
— Onur Mustak Cobanli

In my previous post on this subject, I introduced Scott Meyer’s most important interface design rule: “Make interfaces easy to use correctly and hard to use incorrectly”. As a case in point, we looked at a function which returns a temperature reading from a sensor plus a status code. The temperature sensor might be temporarily or permanently unavailable, so the temperature value can only be relied upon if the returned status is “good”. “Making interfaces hard to use incorrectly” means in this case “making it hard to ignore the returned status”. I claimed that this version of getTemperature is a move in the right direction:

Still, it’s not perfect for at least four reasons. First of all, the [[nodiscard]] attribute is only available if your compiler supports the C++17 language standard. Second, like I explained in my previous post, the C++17 language standard only “recommends” that a compiler issues a warning. Third, even if your compiler does issue a warning, a programmer might disable this/some/all warnings for a particular project, module, or function. But even if none of these reasons apply, a programmer might still dodge checking the status value.

The easiest way to suppress a warning resulting from an unchecked [[nodiscard]] return value is by casting the returned value to void:

You probably think that such developers are stupid and that they are putting their head on the block, that they deserve the pain caused by their deliberate misuse. I certainly agree, but in safety-critical systems, somebody other than the developer might actually suffer the pain, either physically or financially.

In other, more insidious cases, bypassing of [[nodiscard]] can happen accidentally:

Here, the return value is accessed (for logging), so no warning is issued by the compiler. Nevertheless, the value is not checked and thus the code is still buggy. What we need is a status code that enforces that its value is checked. Enter class Checked.

All but the most trivial template code can look intimidating, but Checked is actually quite simple. It acts as a wrapper around a type (Status, in our case) and stores a value of that type. At construction time, a flag called checked is set to false. If this flag is still false when the object is destructed, std::terminate() will be called. The only way to set the flag to true is by invoking the comparison operators == and !=. Here are some examples:

Applied to our getTemperature function, we get

Even though the status value is accessed for logging, std::terminate will still be called because we failed to actually check the status value. The correct usage looks like this:

Did you notice that I tagged the whole Checked class with the [[nodiscard]] attribute? As a consequence, all your functions that return Checked values are implicitly declared [[nodiscard]]. Less typing, less risk of forgetting to add it. Cool!

By using Checked you explicitly communicate to users of your code that they must check the value. The first line of defense is the [[nodiscard]] check at compile-time. If callers cast the returned value to (void) or otherwise fail to check/compare the returned value, they’ll get busted by std::terminate. The upshot of using Checked is that your interfaces are much harder to use incorrectly than by just using [[nodiscard]]. Let’s hope Scott Meyers is satisfied now.

Technical Debt Is Not Bad!

“There once was a Master Programmer who wrote unstructured programs. A novice programmer, seeking to imitate him, also began to write unstructured programs. When the novice asked the Master to evaluate his progress, the Master criticized him for writing unstructured programs, saying, “What is appropriate for the Master is not appropriate for the novice. You must understand Tao before transcending structure.”
The Tao of Programming, Book 3, Verse 2.

I consider Ward Cunningham’s “technical debt” analogy as one of the most important metaphors in software development. According to him, he invented it to explain to his manager why his team needed to do refactorings: like financial debt, technical debt tends to grow over time and the burden gets bigger and bigger due to compound interest.

During the last decade, quality-minded developers have done a great job of educating their managers about technical debt but it seems to me that there is now the notion that all technical debt is bad and must be avoided. But Ward Cunningham never said such a thing — and rightly so.

In business, not all debt is considered bad. It’s a huge difference if someone takes out a 200k loan to buy a flashy sports car or if the owner of a construction company takes out the same 200k loan to buy a bulldozer. The sports car is a pure liability that makes the owner poorer whereas the bulldozer is an investment that will generate money in the future.

The same holds for technical debt. If you initially implement a limited version of a feature (e. g. slow, bloated, lacking proper error-handling) just to enable other teammates to carry on with their own work, that’s good technical debt.

So when does technical debt qualify as good technical debt? To me, good technical debt is

1. taken on consciously
2. managed
3. repaid timely

By contrast, bad technical debt arises out of laziness or incompetence, it lurks in the code base and won’t be repaid. Rather, like credit card debt in real life, more debt is accumulated over time and new loans are taken out just to repay the interest rates of other loans. This is the kind of technical debt that is to be avoided in the first place.

You can use a knife to kill somebody, but you can also use a knife to whittle and prepare food. Surgeons even use knives to save people’s lives. Thus, a knife is neither good nor bad per se and so is technical debt.

A Small Matter Of Interface Design

“Bad design shouts at you.
Good design is the silent seller.”
— Anon

Retired C++ hero Scott Meyers once wrote an article for the renowned IEEE Software magazine titled “The Most Important Design Guideline?“. According to him, the most important design rule is this:

“Make interfaces easy to use correctly and hard to use incorrectly”

I couldn’t agree more. While this rule is applicable to any system, today I want to present it in the light of software interface (API) design. As an illustrative example, I’m going to borrow a method from a former article of mine:

From what you’ve been given, it’s pretty easy to conclude what this routine does and how it’s supposed to be used: ‘getTemperature’ returns a temperature value (let’s say in degrees centigrade) and a status as out parameter. Even without further documentation, it’s not hard to guess that the temperature returned can only be trusted if the status is ‘good’. Most likely, this method reads the temperature value from a hardware sensor that sometimes is busy or dysfunctional.

If you ask me, this design easily passes another important design rule, the so-called “Principle of Least Astonishment“. However, it fails miserably when we apply Scott Meyer’s interface design rule. Why? Because it seduces programmers into using it incorrectly:

As you can see, it’s possible for programmers to get what they want (the temperature) without checking the status value.

The compiler usually doesn’t warn you if you forget to inspect the status variable, because it doesn’t know what ‘getTemperature’ is doing: it might pass it on to another function or store the pointer in a static/global variable.

How can we change the interface such that this mistake is impossible to happen?

Often in such or similar situations, experienced programmers shout “exceptions to the rescue!”. But will exceptions really save us? Let’s see:

Now, ‘getTemperature’ doesn’t provide a status any longer, it rather throws an exception if the temperature value is unreliable or not available. But again, the compiler cannot enforce that programmers provide the try/catch block. Unlike Java, C++ doesn’t have checked exceptions (where checked means that the compiler enforces that exceptions are either caught or declared) and for good reason. So an inconsiderate programmers might naively write:

Even worse, the fact that there is no status parameter any more doesn’t remind them or reviewers at a later point in time that a necessary check has been omitted. Depending on the reliability of the sensor, such code can run for years without problems until it suddenly crashes due to an uncaught exception.

If exceptions don’t help, what does? How about swapping the return value with the status code?

While some would argue that this version is a bit harder to use incorrectly, it’s still possible to do so:

Again, the programmer doesn’t check the status, this time by ignoring the return value. No compiler I’m aware of warns you if you forget to check a function’s return value. Static analysis tools (like PC-lint) do, but who uses them, anyway? And of those good people who do, who enables this particular warning? There are many functions whose return values you almost never care about, like ‘printf’ for example, which returns the number of characters printed, or ‘memcpy’ which returns a pointer to the destination. Therefore, such warnings are usually turned off, even if they are supported.

If you are so lucky and use a C++17 compiler, you can mark a return value as ‘nodiscard’:

Should you now dare to ignore the returned status value, your compiler will report an error. Or will it? Unfortunately not! I don’t know why the people who devised the C++17 standard didn’t go for a compile-time error. Instead, if the return value is ignored by programmers, “implementations should issue a warning in such cases”, they wrote. Arrgh! They didn’t even have the decency to demand a warning. As usual, “should” doesn’t guarantee anything.

Still, I’ve never come across a C++17 conforming compiler that didn’t issue a warning, irrespective of the warning level (unless you force the compiler to suppress all warnings). Therefore, I think that this last version of ‘getTemperature’ is the first that is likely to receive Scott’s blessings.

In a future installment, we’ll explore other alternative versions of ‘getTemperature’ and determine if they comply with the most important interface design rule, which is so important that it bears repeating: “Make interfaces easy to use correctly and hard to use incorrectly”. Stay tuned!