Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. Other Discussions
  3. The Weird and The Wonderful
  4. Avoid return statement in the middle - horror or not?

Avoid return statement in the middle - horror or not?

Scheduled Pinned Locked Moved The Weird and The Wonderful
question
59 Posts 28 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • G Georgi Atanasov

    I have a coding rule - avoid "return" somewhere in the middle of a method, try using local variables to compensate instead. Observing this leads to the following (seen in existing code):

    if(flagA)
    {
    if(flagB)
    {
    if(flagC)
    {
    if(PromtUser())
    {
    DoSomething();
    }
    else
    {
    DoOtherThing();
    }
    }
    else
    {
    DoOtherThing();
    }
    }
    else
    {
    DoOtherThing();
    }
    }
    else
    {
    DoOtherThing();
    }

    How I would have written this is:

    if(flagA)
    {
    if(flagB)
    {
    if(flagC)
    {
    if(PromptUser())
    {
    return;
    }
    }
    }
    }

    DoOtherThing();

    I was wondering how you guys feel about it?

    Thanks, Georgi

    R Offline
    R Offline
    Rob Grainger
    wrote on last edited by
    #48

    Personally, I have no real problem with returns in the middle of a function as long as there are no cleanup considerations, and as long as the procedure remains clear and readable. For cleanup issues, I believe C++ leads the way through RAII (Resource Acquisition Is Initialisation - RAII (Wikipedia), allowing code to be written in whichever manner makes it clearest to read - any resources are then guaranteed to be cleaned up on exit from the routine.

    1 Reply Last reply
    0
    • P PIEBALDconsult

      supercat9 wrote:

      prior to the development of structured programming

      Agreed. When I first learned programming it was in BASIC, which didn't have the wealth of control statements that many other languages have. Since learning Pascal and then C I haven't written a goto (other than within a switch statement).

      supercat9 wrote:

      a structure equivalent to "do{}while(0);"

      Borland C/C++, in C++ mode will handle this:

      # define once for ( int i##__line__ = 1 ; i##__line__ ; i##__line__-- )

      once
      {
      printf ( "Howdy" ) ;

      if ( argc < 3 )
      {
          break ;
      }
      
      printf ( "Howdy" ) ;
      

      }

      Now I'll boot up one of my OpenVMS systems and try it there. Later: %CC-I-DECLINFOR, Placing a declaration in a for loop is a new feature in the C99 standard. Other C compilers may not support this extension. Later yet: I tried it with gcc version 3.2 (mingw special 20020817-1), which I use to pre-process C#, and it wouldn't work. It seems the others will replace __line__ (or __LINE__) before concatenating, but gcc wants to concatenate first and the replacement doesn't happen at all. :mad: I guess I need to find a new C pre-processor. :(

      modified on Monday, December 15, 2008 9:52 PM

      S Offline
      S Offline
      supercat9
      wrote on last edited by
      #49

      The for-loop version is just plain nasty. It wastes a variable and a lot of code. Doing #define once while(0) and then

      do {
      some_code;
      } once;

      would avoid the wasted code. If one wanted to tag both ends of the loop to make clear what was going on, instead of just the tail, one could define some other word as a synonym for "do". Personally, though, I don't like using macros to alter the syntax of a language doing so will make practical something that would otherwise be impractical. To people familiar with do{}while(0); as a means of doing something once, that form will be as readable as anything else. For those unfamiliar with it, the macro would just add confusion. That it would be desirable for a language to include a feature to avoid silly always-true or always-false conditionals does not imply that it is desirable to kludge such features. BTW, if you really want your syntax, and if your code doesn't have to be thread-safe, you can limit the total number of extra variables program-wide to one:

      #define once for(once_var=2;once_var>>=1; )

      The global variable once_var will always be zero or one (doesn't matter which) except between the initial assignment and the initial test, so nested loops and recursion shouldn't pose problems. Still a horrible waste of code, but it should achieve the desired result.

      P 1 Reply Last reply
      0
      • S supercat9

        The for-loop version is just plain nasty. It wastes a variable and a lot of code. Doing #define once while(0) and then

        do {
        some_code;
        } once;

        would avoid the wasted code. If one wanted to tag both ends of the loop to make clear what was going on, instead of just the tail, one could define some other word as a synonym for "do". Personally, though, I don't like using macros to alter the syntax of a language doing so will make practical something that would otherwise be impractical. To people familiar with do{}while(0); as a means of doing something once, that form will be as readable as anything else. For those unfamiliar with it, the macro would just add confusion. That it would be desirable for a language to include a feature to avoid silly always-true or always-false conditionals does not imply that it is desirable to kludge such features. BTW, if you really want your syntax, and if your code doesn't have to be thread-safe, you can limit the total number of extra variables program-wide to one:

        #define once for(once_var=2;once_var>>=1; )

        The global variable once_var will always be zero or one (doesn't matter which) except between the initial assignment and the initial test, so nested loops and recursion shouldn't pose problems. Still a horrible waste of code, but it should achieve the desired result.

        P Offline
        P Offline
        PIEBALDconsult
        wrote on last edited by
        #50

        supercat9 wrote:

        The global variable once_var

        Where do you declare it?

        supercat9 wrote:

        do{}while(0);

        I've only seen that in the GCC documentation where it talks about "swallowing the semi-colon". I've certainly never seen it in production code, and I hope I never do. As others have also said, I don't use do/while, only while. And I don't write a loop that isn't a loop. Wait a minute... doesn't the 0 in while(0) have to exist somewhere as well?

        S 1 Reply Last reply
        0
        • P PIEBALDconsult

          supercat9 wrote:

          The global variable once_var

          Where do you declare it?

          supercat9 wrote:

          do{}while(0);

          I've only seen that in the GCC documentation where it talks about "swallowing the semi-colon". I've certainly never seen it in production code, and I hope I never do. As others have also said, I don't use do/while, only while. And I don't write a loop that isn't a loop. Wait a minute... doesn't the 0 in while(0) have to exist somewhere as well?

          S Offline
          S Offline
          supercat9
          wrote on last edited by
          #51

          PIEBALDconsult wrote:

          Where do you declare it?

          I usually have a module with any global variables that are required by my macros. Not wonderful, but I don't know any better approach in C.

          PIEBALDconsult wrote:

          I've only seen that in the GCC documentation where it talks about "swallowing the semi-colon". I've certainly never seen it in production code, and I hope I never do.

          When trying to write a macro that behaves like a void function but contains an 'if' statement, something like:

          #define foo(x) do {if (x > 0) do_this();} while(0)

          is clearer than:

          #define foo(x) if (x > 0) do_this(); else

          while nonetheless avoiding the difficulties associated with:

          #define foo(x) {if (x > 0) do_this();}

          or worse, the bug-prone

          #define foo(x) if (x > 0) do_this()

          which makes me cringe.

          PIEBALDconsult wrote:

          And I don't write a loop that isn't a loop.

          What would be your preferred way of allowing a procedure to be done in multiple steps and abort at any step, while ensuring that any necessary cleanup would be completed? If you prefer a "goto" label to a do/while(0) structure with break statements, fine. That's actually my usual preference. Can you suggest anything better than the do/while(0) for people who dislike goto?

          P 1 Reply Last reply
          0
          • S supercat9

            PIEBALDconsult wrote:

            Where do you declare it?

            I usually have a module with any global variables that are required by my macros. Not wonderful, but I don't know any better approach in C.

            PIEBALDconsult wrote:

            I've only seen that in the GCC documentation where it talks about "swallowing the semi-colon". I've certainly never seen it in production code, and I hope I never do.

            When trying to write a macro that behaves like a void function but contains an 'if' statement, something like:

            #define foo(x) do {if (x > 0) do_this();} while(0)

            is clearer than:

            #define foo(x) if (x > 0) do_this(); else

            while nonetheless avoiding the difficulties associated with:

            #define foo(x) {if (x > 0) do_this();}

            or worse, the bug-prone

            #define foo(x) if (x > 0) do_this()

            which makes me cringe.

            PIEBALDconsult wrote:

            And I don't write a loop that isn't a loop.

            What would be your preferred way of allowing a procedure to be done in multiple steps and abort at any step, while ensuring that any necessary cleanup would be completed? If you prefer a "goto" label to a do/while(0) structure with break statements, fine. That's actually my usual preference. Can you suggest anything better than the do/while(0) for people who dislike goto?

            P Offline
            P Offline
            PIEBALDconsult
            wrote on last edited by
            #52

            I don't mind it hidden in a macro; I expect to find odd things there, but I don't want to see it hung on the wall for all to see. Anyway, the original post's logic doesn't require anything like that.

            1 Reply Last reply
            0
            • G Georgi Atanasov

              I have a coding rule - avoid "return" somewhere in the middle of a method, try using local variables to compensate instead. Observing this leads to the following (seen in existing code):

              if(flagA)
              {
              if(flagB)
              {
              if(flagC)
              {
              if(PromtUser())
              {
              DoSomething();
              }
              else
              {
              DoOtherThing();
              }
              }
              else
              {
              DoOtherThing();
              }
              }
              else
              {
              DoOtherThing();
              }
              }
              else
              {
              DoOtherThing();
              }

              How I would have written this is:

              if(flagA)
              {
              if(flagB)
              {
              if(flagC)
              {
              if(PromptUser())
              {
              return;
              }
              }
              }
              }

              DoOtherThing();

              I was wondering how you guys feel about it?

              Thanks, Georgi

              C Offline
              C Offline
              coolM
              wrote on last edited by
              #53

              In case of complex preconditions separate those to another function. This prevents structured-ifs and keeps the calling-function readable. If the conditions change (in thight iterative development this always happens), adaption gets easy.

              bool ShouldDoSomething()
              {
              //no returns in middle of method, only on start
              // or everywhere.. ;)
              if(!flagA) return false;
              if(!flagB) return false;
              if(!flagC) return false;
              if(!PromptUser() ) return false;
              return true;
              }

              void callingFunction()
              {
              if( ShouldDoSomething() )
              {
              DoSomething();
              }
              else
              {
              DoOtherThing();
              }
              }

              P 1 Reply Last reply
              0
              • C coolM

                In case of complex preconditions separate those to another function. This prevents structured-ifs and keeps the calling-function readable. If the conditions change (in thight iterative development this always happens), adaption gets easy.

                bool ShouldDoSomething()
                {
                //no returns in middle of method, only on start
                // or everywhere.. ;)
                if(!flagA) return false;
                if(!flagB) return false;
                if(!flagC) return false;
                if(!PromptUser() ) return false;
                return true;
                }

                void callingFunction()
                {
                if( ShouldDoSomething() )
                {
                DoSomething();
                }
                else
                {
                DoOtherThing();
                }
                }

                P Offline
                P Offline
                PIEBALDconsult
                wrote on last edited by
                #54

                Then why not:

                bool ShouldDoSomething()
                {
                return ( flagA && flagB && flagC && PromptUser() ) ;
                }

                which is much easier to read? :-D

                C N 2 Replies Last reply
                0
                • P PIEBALDconsult

                  Then why not:

                  bool ShouldDoSomething()
                  {
                  return ( flagA && flagB && flagC && PromptUser() ) ;
                  }

                  which is much easier to read? :-D

                  C Offline
                  C Offline
                  coolM
                  wrote on last edited by
                  #55

                  you're right... got a bit infected by the horror around.

                  1 Reply Last reply
                  0
                  • P PIEBALDconsult

                    Then why not:

                    bool ShouldDoSomething()
                    {
                    return ( flagA && flagB && flagC && PromptUser() ) ;
                    }

                    which is much easier to read? :-D

                    N Offline
                    N Offline
                    notmasteryet
                    wrote on last edited by
                    #56

                    Be aware of Junioria Developerus animal. Those species may decide that PromptUser() && flagA && flagB && flagC looks prettier. :) Cyclomatic complexity for && and if is the same. Some people believe that cyclomatic complexity number is directly related to code maintenance. And in this thread we did not really lower the number. Is the original code fine as is?

                    P 1 Reply Last reply
                    0
                    • N notmasteryet

                      Be aware of Junioria Developerus animal. Those species may decide that PromptUser() && flagA && flagB && flagC looks prettier. :) Cyclomatic complexity for && and if is the same. Some people believe that cyclomatic complexity number is directly related to code maintenance. And in this thread we did not really lower the number. Is the original code fine as is?

                      P Offline
                      P Offline
                      PIEBALDconsult
                      wrote on last edited by
                      #57

                      notmasteryet wrote:

                      Junioria Developerus

                      I suppose that would be a reason not to distance the tests from the code that uses it. And not to use a lot of negation.

                      1 Reply Last reply
                      0
                      • R Robert C Cartaino

                        [Message Deleted]

                        J Offline
                        J Offline
                        johannesnestler
                        wrote on last edited by
                        #58

                        You are depending on the order of evaluation of your if-statement for your logic to work. Will the PromptUser() operand be evaluated before the entire set of && operations are performed? I think C++ has an "undefined order of evaluation". Who knows. It should be irrelevant. Writing code that depends on order of evaluation is bad programming practice, regardless of language. Sorry, but not knowing how your programming language works is bad practice (operator priority is very important in every language!). And depending on the order of your evaluations is the usual case in real world programming-logic. (I think you are mixing up here with the | and & operators and something a teacher told you once...). I think C++ has an "undefined order of evaluation". Who knows No - and I!!! ;P

                        1 Reply Last reply
                        0
                        • G Georgi Atanasov

                          I have a coding rule - avoid "return" somewhere in the middle of a method, try using local variables to compensate instead. Observing this leads to the following (seen in existing code):

                          if(flagA)
                          {
                          if(flagB)
                          {
                          if(flagC)
                          {
                          if(PromtUser())
                          {
                          DoSomething();
                          }
                          else
                          {
                          DoOtherThing();
                          }
                          }
                          else
                          {
                          DoOtherThing();
                          }
                          }
                          else
                          {
                          DoOtherThing();
                          }
                          }
                          else
                          {
                          DoOtherThing();
                          }

                          How I would have written this is:

                          if(flagA)
                          {
                          if(flagB)
                          {
                          if(flagC)
                          {
                          if(PromptUser())
                          {
                          return;
                          }
                          }
                          }
                          }

                          DoOtherThing();

                          I was wondering how you guys feel about it?

                          Thanks, Georgi

                          M Offline
                          M Offline
                          Megidolaon
                          wrote on last edited by
                          #59

                          Ever thought about using &&?

                          1 Reply Last reply
                          0
                          Reply
                          • Reply as topic
                          Log in to reply
                          • Oldest to Newest
                          • Newest to Oldest
                          • Most Votes


                          • Login

                          • Don't have an account? Register

                          • Login or register to search.
                          • First post
                            Last post
                          0
                          • Categories
                          • Recent
                          • Tags
                          • Popular
                          • World
                          • Users
                          • Groups