Re: return in void functions

From: Jeff Schwab (jeffplus_at_comcast.net)
Date: 01/03/04


Date: Sat, 03 Jan 2004 10:23:14 -0500

Martijn Lievaart wrote:
> On Fri, 02 Jan 2004 15:30:43 -0500, Jeff Schwab wrote:
>
>
>>Why yes, Omniscient One! The design problem was the use of blocks of
>>code having multiple exit points. Most of my typical debug cycle is
>>spent putting "cerr" lines (or gdb break points) at strategic places in
>>the code. Tripling the number of exit points per function almost
>>triples the time it takes to debug a problem.
>>
>>When I throw an exception in a non-trivial program, I include the file
>>name and line number as part of the exception, so I know exactly where I
>>need to start looking when an exception is thrown. Trying to track an
>>issue back to root cause is far more difficult in spaghetti code than in
>>code that avoids mid-block return statements. This should not be news
>>to you.
>
>
> You'll have a hard time tracing exceptions with this design. Why not
> define a trace object, that prints in constructor and destructor? Much
> easier to use and works with multiple returns and exceptions. It's what I
> do if I need this.

So, each time you want to debug a function with multiple return points,
you must:

1) Define a class with member references to all of the function's local
variables; at least, the ones you want to trace.

2) Find a cozy place somewhere before any of the function's return
points, but after all the traced variables have been defined. IME, this
is often impossible. Here is a simplistic case that reflects the common
practice of defining some variable, returning if a check succeeds, and
otherwise defining some other variables:

template< typename T >
void sort_two_objects( T a, T b )
{
      bool already_sorted = a < b;

      // A Trace object defined here cannot trace the value of copy_of_a,
      // even if the return statement is not used.

      if( already_sorted )
      {
           return;
      }

      // A Trace object defined here will not be destructed if the return
      // statement is used.

      T copy_of_a = a;

      a = b;
      b = copy_of_a;
}

> I never was a fan of not allowing multiple exit points, but exceptions
> embedded it in the language, so I guess we better get used to it. I know I
> don't have any problem with it.

Exceptions do provide "extra" exit points, but they are not the same as
return statements. Exceptions carry information back up the call stack
about what went wrong, and why. Often, the information obtained in a
high-level catch block is sufficient, and there is no need to look at
the lower-level code at all. Even when there is such a need, since my
exceptions always include the line number and file number of the
corresponding throw statement, I know exactly which exit point to watch.

> Obviously, multiple exit points, like any language feature can be used
> and mis-used. I concur that they can introduce problems, but only if
> mis-used. My personal guideline in this is that the code should read like
> a story. If not, you have a maintenance problem at least. So this is not
> really related to multiple exit points, but to obfuscated coding.

I've heard that theory before. The fact is that programs are not
stories. When I'm debugging a large piece of code, I have no desire to
start at the beginning and proceed to the point of the problem. The
time required for such an approcach is linear with the number of lines
leading to the point of the problem. By doing instead a binary search
for the problem, debug time is significantly reduced. This approach is
eased greatly by the absence of spurious return statements. Any extra
return statement is what I would call "obfuscated code."

-Jeff

>
> M4
>



Relevant Pages

  • Re: return in void functions
    ... Yes multiple exit points can make ad-hoc ... Exceptions carry information back up the call stack ... debug time is significantly reduced. ...
    (comp.lang.cpp)
  • Re: error handling
    ... >> Lisa Pearlson wrote: ... >>> Imagine I have a socket read function.. ... >>> exit 1 ... > exceptions to return data yet allow additional info.. ...
    (comp.lang.tcl)
  • Re: _ATL_NO_EXCEPTIONS conflict
    ... exceptions are good ways to get back to a clean point where things might be ... work that, for example, might require memory iallocation will be disabled. ... There is nothing more upsetting to a user than to do something, anything, and have the app ... enough to put exit() calls in a GUI app probably has dozens of them, ...
    (microsoft.public.vc.mfc)
  • Re: Sorting a dynamic array
    ... The very first line here shows that with just 1000 items to sort - by ... stand the use of EXIT and CONTINUE in loops - I'm sorry to upset you ... DEBUG ... OSOPEN 'SORTDIR/UN':FNAME TO FVAR ELSE DEBUG ...
    (comp.databases.pick)
  • Re: How do I terminate CWinApp application?
    ... A loop which is processing data which cannot exit cleanly is not ... This turns out to be clumsy in most cases, which is why C++ has exceptions. ... There is always a clean recovery. ... your processing function, when the message pump comes back to life. ...
    (microsoft.public.vc.mfc)