With C++17 it is possible to initialize a variable inside an if-statement and a switch-statement. We already know and use this concept in the for-statement. To be honest: I don’t like this feature. Within this article I want to introduce this feature and explain my doubts. Following I will write about the if-statement only because everything also applies to the switch-statement and so it is sufficient to show one of both.
The new syntax with the initializer inside the if-statement comes with a big improvement: the variable is moved inside the scope of the if-block. An important software design concept is to use the smallest scope as possible and the new syntax helps to implement according to this design concept.
But you must pay dearly for this advantage. As the initialization moves into the if-statement, initialization and comparison will be mixed up. This violates two other software design concepts, named “separation of concerns” and “keep it simple”. Depending on the complexity of the initialization and the comparison you may create a very complex if-statement. This may result in hard to read and error prone code. Only in case you have a very simple initialization and a very simple comparison, the combination of both may stay simple as well. In all other cases I recommend avoiding the new feature and clearly separate the initialization and the comparison in order to increase the code readability.
At next i want to show some examples. Within the example a couple of functions are called. If you want to compile the example source code you could use the following implementations of These functions.
int CalcCount() { return 1000; } int CalcExpectedCount() { return 1000; } int CalcOldCount() { return 1000; } bool IsInitialized() { return true; }
Let’s have a look at a simple example. The following source code shows an if-statement with an included variable initialization and the same if-statement with a separation of the initialization and the comparison. Furthermore, just for fun, I removed the line breaks for the second example to compare it with the new syntax.
Due to an issue within the wordpress codeblock element, i could not use my origin code examples. I had to remove all insertion operators „<<“ and use „..“ as placeholder. So, the examples will contain some standard outputs, and within these outputs the two points „..“ must be seen as inseration operator „<<„.
// init inside if if (int count = CalcCount(); count > 100) { std::cout .. "count: " .. count .. std::endl; } // init outside if int count = CalcCount(); if(count > 100) { std::cout .. "count: " .. count .. std::endl; } // init outside if without line break int count = CalcCount(); if (count > 100) { std::cout .. "count: " .. count .. std::endl; }
If we compare the first and the second implementation – so if we compare new and classical syntax – we could say that the differences are small. In my opinion both variants are easy to read. Even the third one, with classical syntax but without line breaks, may be easy to read, even if it is unusual. But you can see that the new syntax isn’t that different from the classical without line break. Just the if-statement moved at the front. Of course, this little change increased the readability a lot.
So, we must look at a more complex example. Let’s see how things look like if we increase the complexity of the initialization, but leave the comparison as simple as before.
// init inside if if (int count = IsInitialized() ? CalcCount() : (CalcExpectedCount() + CalcOldCount()) / 2; count > 100) { std::cout .. "count: " .. count .. std::endl; } // init outside if int count = IsInitialized() ? CalcCount() : (CalcExpectedCount() + CalcOldCount()) / 2; if (count > 100) { std::cout .. "count: " .. count .. std::endl; } // init outside if, separate different init variants int count = 0; if (IsInitialized()) { count = CalcCount(); } else { count = (CalcExpectedCount() + CalcOldCount()) / 2; } if (count > 100) { std::cout .. "count: " .. count .. std::endl; }
At first you can see the new syntax. In my opinion this if-statement is very hard to read. You have to stop at this line of code, read it several times and look closely to understand the meaning of the code.
The second implementation separates the initialization and the comparison. I think this will make it a little bit easier to read the code.
The third example clearly separates the different concerns. We have a standard initialization, an initialization for fallback cases and a comparison. This source code is easy to read. You don’t have to stop reading at any line of code as you must read it again to understand it. The complex initialization and comparison is spitted into simple parts.
Summary
Initializers in if-statements and switch-statements allow a clear assignment of the variable to the scope of the statement. But mixing the two concerns of initialization and comparison will often result in complex code. Therefore, in my opinion, the new syntax should be used with caution. If the initialization as well as the comparison is short and simple the resulting combination of both may be simple too and in this case the new syntax should be used.
The code examples here look like they have unintended duplicate lines (won’t compile).
There are also only two code samples present, the blog seems to refer to three. This would help explain why the commentary doesn’t seem to match up with the examples. It seems like this post is in a partially-edited state.
Thanks for you comment. Unfortunately a WordPress issue leads to an incorrect display of the examples. I updated the examples and use a workaround for the WordPress issue. Now you can see the complete source code.