Optimistic vs pessimistic code

Hi, do you check for success or for failure in your code? I mean, being pessimistic is great, just compare this piece of code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//#1
if(it_works())
  {
      // everything's ok, continue...
      if(can_continue)
      {
          // everything's ok, continue...
          if(operation_successful)
          {
              // wer'e done
              return true;
          }
          else
          {
              cout <<"Never give up, my friend!";
              return false;
          }
      }
      else
      {
          // ...
          return false;
      }
  }
  else
  {
      // clenanup
      return false;
  }

to this
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//#2
  if(it_works()==false)
    return false;
 // everything's ok, continue...
  if(can_continue==false)
  {
      cout <<"Life sucks. Im outta here";
      return false;
  }
  // everything's ok, continue...
  if(operation_successful==false)
  {
      //...
      return false;
  }
 cout <<"nothing went wrong";
 return true;

The second example is much easier to read . But I see a lot of code that is more similar to my first example. Are there any reasons why? and what's your style?
I don't write or use code that can fail in an undesirable way, so neither of the above are acceptable to me. (Don't ask me to elaborate, I had a whole topic on it and it just made people confused)
It's all about the context of the program. If you need a network connection for your application then that isn't something that you can necessarily control on the end users side. Also, they might want to be made aware what the problem with your program is so that they can plug the network cable in, add an exception to their firewall etc.

@ LB: You don't happen to have a link to that thread do you? Or possibly the title so I can search for it? It sounds like a neat idea but I don't see how it's possible.
Whenever the functionality of your code depends on something else and you can check that the something else is actually working or valid, then you probably should. Because that something else might not be the same in all instances, or might change on you. So what if you have nothing checking all of those things, then if one of those things has an issue, you have to track down the error, potentially wasting many hours. If the code base is very large it could be an absolute nightmare.

@LB: Why give a completely vague statement and say you wont elaborate. It's like you just said this topic is not applicable to me but I wont say why.
Last edited on
@Computergeek01: Trying to find it...

@htirwin: just to state that there is a third option that was not mentioned?
I do this for testing:
1
2
3
4
5
6
7
8
9
// if success
if(it_works()){
      // do something
}

// if fails
if(!it_works()){
      // do something
}

You can't anticipate every failure so you always have to error check. Some anomalies can happen that makes your data act different than what you expect. I just don't worry about whether my code is optimistic or pessimistic so long as it gets the job done.
@BHX Specter: Why do you call the function twice like that?
It was an example to show how I do my checks as to if I am checking if the function succeeds or fails.
I think LB meant why not use an else statement instead of checking weather a function returns true then check if the same function returns false.

1
2
3
4
5
6
7
8
if(itWorks())
{
    //do something
}
else
{
    //do something else
}
I know what he meant, but that is why I said they were examples. I didn't mean I did both in the same file. Null asked what method we use, but I was showing an example of how I do my checks for both.

He did:
1
2
3
4
5
6
7
8
9
10
11
12
if(itWorks()){       // optimistic code
////do something
}else{
///do something
}

or 
if(itWorks() == false){     // pessimistic code
/// do something
}else{
/// do something
}


Where as I do:
1
2
3
4
5
6
7
8
9
if(itWorks()){     // optimistic code
////do something
}

or 

if(!itWorks()){     // pessimistic code
/// do something
}
Optimistic vs pessimistic code
I use exceptions. So my code looks like this:
1
2
3
4
5
6
7
8
9
10
11
12
try {
    doSomething();
    doSomethingElse();
    finishingTouches();
    //...
    //...
} catch(io_exception& e) {
    //Show messagebox to user and abort transaction
} catch(logic_erroe& e) {
    //Try to make sense of error and handle it 
    //(usually by showing messagebox and aborting transaction.)
}
LB wrote:
I don't write or use code that can fail in an undesirable way
That is hard to do if you take into account morons user abilities:

Problem 0: User decided it is a good idea to make whole MyDocuments folder read only.
Ok, my bad, should have used %Appdata% from the beginning.

Problem 1: User thought that file database in program folder is suspicious and decided to delete it.
Apparently he had some sort of messagebox blindness, so it took 15 minutes to make him confess that there was messagebox telling why program isn't runnng.

Problem 2: User launches program and then removes database file because he still doesn't like it.
Sadly he is technically my superior, so I cannot say ewerything I want to him.

Problem 3: Another user launches program from flash drive and plug it off immideatly after.
FINE. Solving this and previous problems by loading everything that might be needed in memory on program startup. I hope you like 2500% memory usage increase.
Last edited on
Man, it almost sounds like your superior is Pointy Haired Boss.
I'd rather call it positive vs negative logic.

1
2
3
4
if(itWorks())
{
////do something
}


vs

1
2
3
4
if(!itWorks())
{
/// do something
}

optimistic/pessimistic sounds as if you could omit a possible case. Don't do that

I always use the positive logic. The reason is !. It's way to easy to forget the ! and hence having a completely wrong statement. So even if there's nothing to do in the positive case I would prefer to write:
1
2
3
4
5
6
if(itWorks())
  ;
else
{
////do something
}
The advantage of writing so is that if later there is something to do in the positive case there's not much to change
I try to not use empty if body. I even do not use else branches when checking preconditions/error states:
1
2
3
4
5
6
if (inp < 0) {
    return -1;
    //or throw std::domain_error(/*...*/)
}
return std::sqrt(inp);
//Versus →
if (inp < 0) {
    return -1;
    //or throw std::domain_error(/*...*/)
} else {
    retunn std::sqrt(inp);
}
I use branching when need to do different actions in different cases is dictated by function logic, not when checking input invariants or trying to do a shortcut by early return.
coder777 wrote:
The reason is !
1
2
3
if(not itWorks()) {
//...
}
Alternative operators can increase readability in some cases. However it does not solve issue of not noticing missing !, sadly.
It's way to easy to forget the !
Is it? I don't think it has happened to me more than three times ever.
Most people will refactor code like that on sight because, let's face it, even if the negation operator was a problem, that code just looks stupid.
@OP,
Seeing your first code example reminded me of an example I saw in Steve McConnell's Code Complete (2nd. ed.) which suggests that the first code sample is more desirable. (Chapter 15, Section 1 if you've got a copy).

Doing it the way the first segment shows puts your nominal case at the beginning, so a potential reader of this code can quickly see the normal path through the code. IMO, #1 was way easier to read than #2.

The same section calls out if statements that use null clauses like coder777 did as a "Coding Horror". It introduces needless typing and doesn't read as well as just negating the predicate.
Austin J wrote:
Man, it almost sounds like your superior is Pointy Haired Boss


I was thinking exactly that! Unfortunately, that's a large majority of users...
Overall, I do "pessimistic" coding like the second example. However, like it's been said on here many times, it's all about context. If it's a failure is not crucial to the program, then I keep the most likely path the shortest and most efficient (it could look like either example). If a failure is crucial, then I pessimistically check through the code like the second example.
Yes: offense is the best way to discuss coding style. I'm done with it
Topic archived. No new replies allowed.