What errors are saved by brevity? [closed] - c++

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 7 years ago.
Improve this question
"C++ Primer" (5th edition) suggests on page 149 that a brief code can be less error-prone than a longer alternative. It brings the following line of code to serve as an example:
cout << *iter++ << endl;
It claims that the above line is less error-prone than the alternative:
cout << *iter << endl;
++iter;
To me, even though the meaning of *iter++ is clear, this expression still requires a non-zero mental effort to parse and so the second version is more readable. So, I want to understand: what is more error-prone about the second version?

I also do not agree with the author.
Usually each code snippet has a tendency to be changed in the future.
For example this statement
cout << *iter++ << endl;
can be changed the following way
cout << *iter++ << ... << SomeFunction( *iter ) << endl;
In this case the code will have undefined behaviour because the order of evaluation of function arguments is unspecified.
So in my opinion this code snippet
cout << *iter << endl;
++iter;
is less error-prone.:)
Introducing side-effects in a code snippet does not make it less error-prone.
Moreover in the code snippet you showed there is no logical relation between the increment of the iterator and outputting its value.
cout << *iter++ << endl;
So it is unclear why the iterator is incremented in this statement.
Separating this statement into two statements makes the code snippet more clear because it seems that the incrementing is related to some other parts of the code.
The brevity makes the code more expressive. But it does not mean that it necessarily makes also the code less error-prone.:)

The thing is, when you have your function containing a few lines on code, each one of them is treated as a "step" to achieve some goal. When you read such a function you read each line and think what it does and why. In your example,
cout << *iter << endl;
++iter;
logically could be one step: "when iterating over the container, write each element to cout". It's because when you forget either of these lines, the whole step is incorrect. Of course, this very example is not particularly great, because it's not hard to come up with a code, in which the two lines are two different logic steps. However, I assume the author meant, that by writing
cout << *iter++ << endl;
you protect yourself from forgetting one part of a logic step as well as you make a signal for a reader that this is one logic step.

I can think about the lines being reordered for some reason (maybe they became separated by some other code and it was later modified), or an if/for/while being added, either without braces or with them wrongly placed:
++iter;
cout << *iter << endl;
if (some_condition)
cout << *iter << endl;
++iter;
while (something_happens)
{
cout << *iter << endl;
}
++iter;
In this small example, the bugs are quite obvious, but that may not be the case when you have a lot more lines.
(And yes, I know the indentation in the 2nd and 3rd examples should be corrected, but sadly I've seen lots of examples like these).

I couldn't disagree with the author more.
The expression *iter++ does two different things to iter - it dereferences it and increments it. Yes, the order is defined, but understanding the results of two actions on a single variable in a single expression requires inherently more brainpower than something which has only one effect on a single variable.
One of the most reliable ways to increase errors from a developer is to unnecessarily increase the brainpower needed to understand what their code actually does.
The virtue of breaking the effects into two distinct statements is that it is easier to understand.
The other phenomenon is that programmers who are taught to include two effects on a single variable in a single statement are more likely to craft expressions with even more effects on some poor variable. Apart from making their code even less comprehensible, it also increases the likelihood of undefined behaviour (since any expression that modifies any variable more than once in a single expression has undefined behaviour).

It might be worth comparing to similar constructs in other languages.
In python, to iterate over a sequence, we use a generator. There is essentially only one operation you can do with a generator: call next which obtains an element and advance the generator. Iteration, when done manually, is done by repeatedly calling next to get the terms of the sequence until it raises StopIteration to signal the end of the sequence.
In java, to iterate over a sequence, we us an Iterator. There is essentially only one operation you can do with an iterator: call next which obtains an element and advances the iterator. Iteration, when done manually, is done by repeatedly calling next to get the terms of the sequence until hasNext returns false to signal the end of the sequence.
In C/C++... we often want to get an element and advance through the sequence. It has been long established (AFAIK before C++ even existed) that this operation is *p++.
The only reason we are even contemplating the idea of breaking this into two steps -- one step being to get the current element and the other step being to advance to the next term -- is an artifact of an implementation detail.
In a situation where one is truly thinking of these two steps as being separate, independent things, then it would be best to keep them as separate expressions.
But it is relatively well established that that is not how people are thinking -- people are thinking in terms of "getting an element and advancing the iterator". Iteration, when done manually, is done by repeatedly invoking *iter++ to get the terms of the sequence, until iter == end_iter returns true to signify the end of the sequence.
When thinking this way, splitting the one conceptual step into two syntactically separate elements (*iter and ++iter) is more error prone than keeping it as a single step.

Not a good example, because you shouldn't use while without braces, but it could lead to errors like this: In this case you would have an infinite loop when adding the while.
while (*iter)
cout << *iter << endl;
++iter;
I think it is a bad example! Much better would be an example, where you have multiple dependent steps. Then someone copies some steps to another function, but misses some lines, which don't look they are semantically needed.

Related

Would it be more efficient to have the \n character in the same string literal than to have an extra set of "<<"?

I was wondering if in code such as this:
std::cout << "Hello!" << '\n';
Would it be more efficient to have the \n character in the same string literal, as in this case, "Hello!"? Such as the code would then look like this:
std::cout << "Hello!\n";
I am aware that things such as these are so miniscule in difference whether one is more efficient than the other (especially in this case), that it just doesn't matter, but it has just been boggling my mind.
My reasoning:
If I am not mistaken having the \n character in the same string literal would be more efficient, since when you have the extra set of the insertion operator (operator<<) you have to call that function once again and whatever is in the implementation of that function, which in this case, in the Standard Library, will happen just for one single character (\n). In comparison to only having to do it once, that is, if I were to append that character to the end of the string literal and only have to use one call to operator<<.
I guess this is a very simple question but I am not 100% sure about the answer and I love to spend time knowing the details of a language and how little things work better than others.
Update:
I am working to find the answer myself as for questions such as this, it is better for one to try and find the answer for themselves, I haven't worked with any Assembly Code in the past, so this will be my firs time trying to.
Yes; but all of the ostreams are so inefficient in practice that if you care much about efficiency you shouldn't be using them.
Write code to be clear and maintainable. Making code faster takes work, and the simpler and clearer your code is the easier to make it faster.
Identify what your bottleneck is, then work on optimizing that by actually working out what is taking time. (This only fails when global behaviour caused global slowdowns, like fragmentation or messing with caches because).

What are the historical reasons C languages have pre-increments and post-increments?

(Note: I am not asking about the definitions of pre-increment vs. post-increment, or how they are used in C/C++. Therefore, I do not think this is a duplicate question.)
Developers of C (Dennis Ritchie et al) created increment and decrement operators for very good reasons. What I don't understand is why they decided to create the distinction of pre- vs post- increments/decrements?
My sense is that these operators were far more useful when C was being developed than today. Most C/C++ programmers use one or the other, and programmers from other languages find the distinction today bizarre and confusing (NB: this is based solely on anecdotal evidence).
Why did they decide to do this, and what has changed in computation that this distinction isn't so useful today?
For the record, the difference between the two can be seen in C++ code:
int x = 3;
cout << "x = 3; x++ == " << x++ << endl;
cout << "++x == " << ++x << endl;
cout << "x-- == " << x-- << endl;
cout << "--x == " << --x << endl;
will give as an output
x++ == 3
++x == 5
x-- == 5
--x == 3
Incrementing and decrementing by 1 were widely supported in hardware at the time: a single opcode, and fast. This because "incrementing by 1" and "decrementing by 1" were a very common operation in code (true to this day).
The post- and predecrement forms only affected the place where this opcode got inserted in the generated machine code. Conceptually, this mimics "increase/decrease before or after using the result". In a single statement
i++;
the 'before/after' concept is not used (and so it does the same as ++i;), but in
printf ("%d", ++i);
it is. That distinction is as important nowadays as it was when the language C was designed (this particular idiom was copied from its precursor named "B").
From The Development of the C Language
This feature [PDP-7's "`auto-increment' memory cells"] probably suggested such operators to Thompson [Ken Thompson, who designed "B", the precursor of C]; the generalization to make them both prefix and postfix was his own. Indeed, the auto-increment cells were not used directly in implementation of the operators, and a stronger motivation for the innovation was probably his observation that the translation of ++x was smaller than that of x=x+1.
Thanks to #dyp for mentioning this document.
When you count down from n it is very important whether is pre-decrement or post-decrement
#include <stdio.h>
void foopre(int n) {
printf("pre");
while (--n) printf(" %d", n);
puts("");
}
void foopost(int n) {
printf("post");
while (n--) printf(" %d", n);
puts("");
}
int main(void) {
foopre(5);
foopost(5);
return 0;
}
See the code running at ideone.
To get an answer that goes beyond speculation, most probably you have to ask Dennis Ritchie et al personally.
Adding to the answer already given, I'd like to add two possible reasons I came up with:
lazyness / conserving space:
you might be able to save a few keystrokes / bytes in the input file using the appropriate version in constructs like while(--i) vs. while(i--). (take a look at pmg s answer to see, why both make a difference, if you didn't see it in the first run)
esthetics
For reasons of symmetry having just one version either pre- or postincrement / decrement might feel like missing something.
EDIT: added sparing a few bytes in the input file in the speculation section providing, now providing a pretty nice "historic" reason as well.
Anyways the main point in putting together the list was giving examples of possible explanations not being too historic, but still holding today.
Of course I am not sure, but I think asking for a "historic" reason other than personal taste is starting from a presumtion not neccesarily true.
For C
Let's look at Kernighan & Ritchie original justification (original K&R page 42 and 43):
The unusual aspects is that ++ and -- may be used either as prefix or
as postfix. (...) In the context where no value is wanted (..) choose
prefix or postfix according to taste. But htere are situations where
one or the other is specifically called for.
The text continues with some examples that use increments within index, with the explicit goal of writing "more compact" code. So the reason behind these operators is convenience of more compact code.
The three examples given (squeeze(), getline() and strcat() ) use only postfix within expressions using indexing. The authors compare the code with a longer version that doesn't use embedded increments. This confirms that focus is on compactness.
K&R highlight on page 102, the use of these operators in combination with pointer dereferencing (eg *--p and *p--). No further example is given, but again, they make clear that the benefit is compactness.
For C++
Bjarne Stroustrup wanted to have C compatibility, so C++ inherited prefix and postfix increment and decrement.
But there's more on it: in his book "The design and evolution of C++", Stroustrup explains that initially, he planned have only one overload for both, postfix and prefix, in user defined classes:
Several people, notably Brian Kernighan, pointed out that this
restriction was unnatural from a C perspective and prevented users
from defining a class that could be used as replacement for an
ordinary pointer.
Which caused him to find the current signature difference to differentiate prefix and postfix.
By the way, without these operators C++ would not be C++ but C_plus_1 ;-)
Consider the following loop:
for(uint i=5; i-- > 0;)
{
//do something with i,
// e.g. call a function that _requires_ an unsigned parameter.
}
You can't replicate this loop with a pre-decrement operation without moving the decrement operation outside of the for(...) construct, and it's just better to have your initialization, interation and check all in one place.
A much larger issue is this: one can over-load the increment operators (all 4) for a class. But then the operators are critically different: the post operators usually result in a temporary copy of the class instance being made, where as the pre-operators do not. That is a huge difference in semantics.
The PDP-11 had a single instruction that corresponded to *p++, and another for *--p (or possibly the other way round).

if statements in c++

So I have been writing in c++ for a few weeks now and can't help but feel that I am using too many if statements in my code. I am aware of while, do while, and for loops but when given the scenario I always use if statements. I guess I am not exactly aware of how I could use a different method. I just finished a project and there are if statements everywhere. Could one of you guys please explain to me how I can change some of these if statements into something different but still functional? I am really just looking for guidance in the right direction. Any help will be appreciated. Thank you guys!
If statement #1 that bugs me:
if (x >= 1)
{
setx_Position(3);
sety_Position(500);
cout << "Soldier moves: " <<getx_Position()<<", "<<gety_Position()<< " ";
cout << endl;
}
else
{
cout << "Soldier moves: " <<getx_Position()<<", "<<gety_Position()<< " ";
cout << endl;
}
return 0;
Second if statement bugging me is :
a--;
if (a >= 0)
{
cout << "Soldier fires weapon : Pistol " << "(" << a << " bullets left)" << endl;
}
else if (x <= 0)
{
cout << "Soldier fires weapon : NO WEAPON FIRED! (DEAD)" << endl;
}
return 0;
Both of these just feel lengthy and unnecessary to me. How could I get the same results with a much cleaner look? Or is this the best way to do it?
There's nothing wrong with having to use if statements, they're often a must when you need to perform an action conditionally. As for improving your snippets, an obvious thing to do in the first one is to move the common sections of code outside the if-else block.
if (x >= 1)
{
setx_Position(3);
sety_Position(500);
}
cout << "Soldier moves: " << getx_Position() << ", " << gety_Position() << " ";
cout << endl;
The second one looks pretty good as is. The only thing I see that could (arguably) be an improvement is to remove a--; and change the if condition to if(--a >= 0)
Well, Turing would be proud for so much loyalty to the behaviour of the original Turing machine but in modern C++ there are other weapons in your arsenal, I suggest to read a book about patterns, maybe this one, there is not such thing as "optimizing" or suggest something starting from your snippets, it's merely pointless because a single if can't really impact on your productive skills, you need a foundation about advanced C++ techniques.
well an if statement is a very common thing to use in code, especially in logic heavy sections, such as game code.
in c++ one way to avoid lots of if blocks for different things is to use Polymorphism, or function pointers.
switch statements can also be good.
I can't really see any better way of doing your two examples, except for the optimization of example one mentioned by Praetorian
A great deal depends upon what sort of logic you're willing to use to avoid an if statement.
For example, let's consider your second example. You really have pretty much the same actions in both legs of the if statement -- you mostly just supply different data to write to the output. If you don't mind some minor changes in wording, it's pretty easy to eliminate the if statement entirely:
static char const *prefixes[] = {
"Soldier tries to fire (but has ",
"Soldier fires Weapon: Pistol ("
};
std::cout << prefixes[--a >= 0] << a << " bullets left)\n";
It's a little hard to say whether I'd recommend this or not. At first glance, the code is obviously a lot simpler and cleaner -- no conditions or if statements to deal with at all. At the same time, for somebody who's unaccustomed to this style, it would undoubtedly lead to some serious head-scratching.
please explain to me how I can change some of these if statements into
something different but still functional?
If you need to make decisions, you need if statements. Thing is, if you have many many of them littering the code I agree with you that you would want to think long and hard about how to make the code more readable by performing the logic in other ways. (Remember, (paraphrasing) code is mainly for reading; and only occasionally for the computer to execute). You probably don't want code that is too 'procedural', i.e. one long stream of C-like code. Create classes/objects that react to your simulation, thus encapsulating much of the logic. And please, don't have massively nested if/else spaghetti.
Another reason to reduce the number of if's is that if blocks are the most likely parts of your code to contain bugs, and are the hardest to test. (You are writing tests, right?)
But as others have said, there's not enough context. Oh, and name your variables like "NumBulletsRemaining" instead of x or whatever :)

What's the difference between these 2 'if' and 'if-else' statements?

What is the difference between 2 if statements and 1 if-else statement?
int x;
cin >> x;
if (x==10)
cout << "Hello";
if (x!=10)
cout << "Hey";
int x;
cin >> x;
if (x==10)
cout << "Hello";
else
cout << "Hey";
In practice, the optimizer will probably make them exactly the same. The best thing to do in these cases is to try it - look at the assembly output of your compiler, and you'll see exactly what the difference is.
The difference is that in the second case the condition is checked and computed only once.
In the first example both are evaluated, always.
In the second example if first is true, it never gets to second.
The most important difference (to my mind) is that the first form is harder to read and is more error-prone.
The second form reads more like English: "If x is 10 then do this, else do that" whereas the first form essentially makes the two clauses unrelated. It's error prone because if you decide that the threshold 10 needs to change then you need to update it in two places rather than just one.
In terms of execution speed, I'd be very surprised if there is any difference at all. There will be two evaluations with the first form but that's the least of the problems. It's certainly not the sort of thing you should waste time optimising.
There is no visible output difference. However, it does make your code easier to read if you use the ladder one
if (x==10) //matches only if x is number 10 , then processor jump to next line i.e.
if (x!=10) // matches only if x is not number 10
where as
other if checked only , if the number is either 10 or anything else then 10.
In a way both will result same, but its just matter of statements.
so
in first example, both lines of if will be executed
in second example either of one is executed
So its better to use second one for performance
From a maintainability point of view the first one
violates the DRY principle.
is a lot harder to understand and modify. Not with a trivial condition, like here, but with a nice long condition you'll either have to just cut 'n paste the condition and slap a ! in front, or try to remember how De Morgan's laws were formulated... And some day that will fail, and the inverted if will fail to be the exact opposite of the first....
So, else is the way to go.
In the first block both if statement will run by the compiler...
But int the second one only 1 statement will run as both are linked with a single condition . Either if can be true or else can be true
You can understand this as considering 1st one as 'and' type
And the 2nd one as 'or' type

printing using one '\n'

I am pretty sure all of you are familiar with the concept of the Big4, and I have several stuffs to do print in each of the constructor, assignment, destructor, and copy constructor.
The restriction is this:
I CAN'T use more than one newline (e.g., ƒn or std::endl) in any method
I can have a method called print, so I am guessing print is where I will put that precious one and only '\n', my problem is that how can the method print which prints different things on each of the element I want to print in each of the Big4? Any idea? Maybe overloading the Big4?
Maybe I don't understand the question completely because it is asked rather awkwardly, but can't you just have a function called newline that receives an ostream as an argument, and then simply prints '/n' to that output stream? Then you can just call that infinitely many times, while still abiding the arbitrary "one newline" rule.
e.g.
(edit: code removed, "smells like homework")
print should take a parameter containing the information to output to the screen (sans '\n') and then call the c++ output method with in-line appending the '\n' to the passed in information.
note: no code 'cause this smells like homework to me...
I'm not sure I completely understand what you're trying to accomplish. Why is it that you can only use one newline? What makes it difficult to just write your code with only one newline in it? For example, I've done stuff like this before.
for(int i = 0; i < 10; i++) {
cout << i << " ";
}
cout << std::endl;
If you need something more complicated, you might want to make some sort of print tracker object that keeps a flag for whether a newline has been printed, and adjusts its behavior accordingly. This seems like it might be a little overly complicated though.