[comp.lang.c] Single exit standard. Was: Coding Standards.

rmartin@clear.com (Bob Martin) (11/20/90)

In article <IMP.90Nov16123956@marvin.Solbourne.COM> imp@marvin.Solbourne.COM (Warner Losh) writes:
>In article <1990Nov10.191840.21113@clear.com> rmartin@clear.com (Bob Martin) writes:
>: The lack of standard coding practice IS a big problem for software
>: maintenance.
>
>Agreed.  However, a bad coding standard can make life miserable for
>everybody.
>

Yet _NO_ standard is still worse

>: It specifies that functions should have single entrance and single
>: exit points
>
>This is a bogus restriction, at least in terms of a single exit point.
>

Allow me to make a few additions to your piece of code...

>	if (allocate-memory) {
>		do some stuff
>		if (get-more-memory) {
>			do more stuff
>			if (open-file) {
>				do even more stuff
>				if (alloc more memory) {
>					...
>					status = OK;
---					free more memory
>				}
>				else {
---					LogError(1);
>					status = NO_MEM
---					}
---				close file
>			}
>			else {
---				LogError(2);
>				status = NO_FILE
---				}
---			free-more-memory
>		}
>		else {
___			LogError(3);
>			status = NO_MEM
---			}
___		free allocated memory
>	}
>	else {
___		LogError(4);
>		status = NO_MEM
---		}
>
>	return status;
>

Here we see one of the real benefits of the technique.  The free
calls and close calls can be performed at the correct place,
and it is trivial to insure that they are present and correct.
The ErrorLogs pinpoint exactly which place in the code is failing.

Your assertion that simple programs need not go through this is 
valid so far as it goes.  But how many programs start simple and
then grow...   The burden is not very great, the complexity
of the code is reduced, and the code is more robust against
growth. 
-- 
+-Robert C. Martin-----+:RRR:::CCC:M:::::M:| Nobody is responsible for |
| rmartin@clear.com    |:R::R:C::::M:M:M:M:| my words but me.  I want  |
| uunet!clrcom!rmartin |:RRR::C::::M::M::M:| all the credit, and all   |
+----------------------+:R::R::CCC:M:::::M:| the blame.  So there.     |

mat@mole-end.UUCP (Mark A Terribile) (12/09/90)

> >: The lack of standard coding practice IS a big problem for software
> >: maintenance.

The worst problem in maintenance (he said dogmatically) is that the
maintenance programmers rarely ensure that the code `typography' is the
same quality it should be in new code.  Granted, often managers take
lines of code with difference as some sort of a measure of badness of a
fix.  Unfortunately, tweaks instead of thorough changes in code can
produce precocious schlerosis.

	. . .
> >: It specifies that functions should have single entrance and single
> >: exit points
> >
> >This is a bogus restriction, at least in terms of a single exit point.
> >
 
> Allow me to make a few additions to your piece of code...
 
> >	if (allocate-memory) {
> >		do some stuff
> >		if (get-more-memory) {

	etc ...

Let me suggest that the worst problem here is not the addition of code,
nor the need to ensure that resources are properly managed as scopes are
entered and left, but that the program's typographical structure and
decision organization have not been kept up with the extra functionality
of the code.

> Here we see one of the real benefits of the technique.  The free
> calls and close calls can be performed at the correct place,
> and it is trivial to insure that they are present and correct.
> The ErrorLogs pinpoint exactly which place in the code is failing.

I disagree strongly with the assertions.  First, the error returns/logging
are widely seperated from the tests which recognize them; they are located
WAY down below AND they interrupt the text of non-error-case code.

I grant that the free and close calls are attached to scope.  Unfortunately,
that doesn't guarantee that someone who picks the code up will get the
resource-management correct EVEN THOUGH it follows the simple principle
of following the scope.  (In C++, where you can program such that the
resources are released automatically when the program goes out of scope,
it's another matter ... but C++ also handles  return s  properly.)

What we have is a `Lazy Man's Load.'  Let me try it another way ... keeping
code linear, so that conditions are not nested (and especially so that the
small and rare case does not tag along on the end of the large and common
case) AND keeping track of resource management explicitly.


	if( allocate-memory FAILS )
	{
		LogError(4);
		return NO_MEM;
	}

	do some stuff

	if( get-more-memory FAILS )
	{
		LogError(3);
		free allocated memory
		return NO_MEM
	}

	do more stuff

	if( open-file FAILS )
	{
		LogError(2);
		free-more-memory
		free-memory
		return NO_FILE
	}


	do even more stuff

	if( alloc more-more-memory FAILS )
	{
		LogError(1);
		close file
		free-more-memory
		free-memory
		return NO_MEM
	}

	do even more more stuff

	free more-more-memory
	close file
	free-more-memory
	free-memory

	return OK;

The really serious STRUCTURAL problem is that you have a problem that
requires an `interesting' sequence of attempted resources and do-stuff's.
If a resource can be released early, it should be.  We might have


	{
		declare file variable
		if( open-file FAILS )
		{
			LogError(2);
			free-more-memory
			free-memory
			return NO_FILE
		}

		do even more stuff
	}

In no case, in such code, should the `do-stuff's be more than one or two
lines!  Use function calls, whatever.  Whether you use the linear approach
(which I strongly endorse) or the manually-manage-resources-by-scope approach
(which I don't endorse), you need to dedicate a whole function to expressing
just the resource management.  Use other functions to express the  do-stuff's
if they are non-trivial.  Especially if the do-stuff's involve loops, put
them in other functions so that the loop structure does not add its clutter
to the resource management flow structure.

It's really important that the exceptional, there's-a-problem-with-resources-
not-algorithm cases be written right after the tests that detect them; don't
carry them downward and let them interpose into the program text lines and
lines below.
-- 

 (This man's opinions are his own.)
 From mole-end				Mark Terribile