http://www.perlmonks.org?node_id=298802


in reply to Short routines matter more in OO?

I think the length of a routine, whether procedural, functional or OO, is less important than the maximum nesting level.

To illustrate what I mean, consider this concocted ( and very possibly wrongly coded ) piece of C.

int build_table( int x, int Y, double **values, char *s ) { int xi, yi; double next; if( x > 0 && x < 10 ) { if( y > 0 && y < 10 ) { if( values ) { if( !mem_guard( values, sizeof( double ) * x * y ) ) { if( s ) { if( !mem_guard( s, ( ( x * 11) + 1) * y ) ) { for( yi=0; yi < y; yi++ ) { for( xi; xi < x; xi++ ) { int w = 10; int p = 3; next = values[ yi ][ xi ]; if( ( next - 1000.0 ) < 0.001 ) { p = 5; } else if( ( next - 100.0 ) ) < 0.00 +001 ) { p = 6; } s += sprintf( s, "%*.*e ", w, p, n +ext ); } *s++ = "\n"; } *s++ = "\n"; } else return ERROR_BUFFER_TOO_SMALL | 4; } else return ERROR_BAD_ARG | 4; } else return ERROR_BUFFER_TOO_SMALL | 3; } else return ERROR_BAD_ARG | 3; } else return ERROR_BAD_ARG | 2; } else return ERROR_BAD_ARG | 1; return 0; }

And contrast that with

int build_table( int x, int Y, double **values, char *s ) { int xi, yi; double next; if( x < 0 || x >= 10 ) return ERROR_BAD_ARG | 1; if( y < 0 || y >= 10 ) return ERROR_BAD_ARG | 2; if( !values ) return ERROR_BAD_ARG | 3; if( mem_guard( values, sizeof( double ) * x * y ) ) ERROR_BUFFER_T +OO_SMALL | 3; if( !s ) return ERROR_BAD_ARG | 4; if( mem_guard( s, ( ( x * 11) + 1) * y ) ) return ERROR_BUFFER_TOO +_SMALL | 4; for( yi=0; yi < y; yi++ ) { for( xi; xi < x; xi++ ) { int w = 10; int p = 3; next = values[ yi ][ xi ]; if( ( next - 1000.0 ) < 0.001 ) { p = 5; } else if( ( next - 100.0 ) ) < 0.00001 ) { p = 6; } s += sprintf( s, "%*.*e ", w, p, next ); } *s++ = "\n"; } *s++ = "\n"; return 0; }

Critiques of my (very rusty) C code, and whether anyone would actually code as in the first example (I know I did many moon ago, when "structured programming" was all the rage!) aside, hopefully, most people would agree that the second example is much easier to understand than the first although they do the same thing in essentially the same way.

The main reason the second example is easier to read, IMO, is because there is a clear delineation between the two function of the code. The first block is parameter checking and error reporting. Once you move beyond that, you step cleanly into, and can concentrate your thoughts upon the primary purpose of the routine. By un-nesting the code, the length of the routine has barely changed, but the ability of the programmer to concentrate their thoughts has changed markedly. It becomes much easier to concentrate on a shorter section of the routine.

In the first example, validating the error checking, becomes a nightmare task requiring that you page back and forth up and down the code, mentally aligning nesting levels. In the second, the need for either just disappears.

I have seen advocations that once a small number of levels of nesting has been reached, the inner levels should be consigned to another layer of subroutine. Whilst this would allow the second section to be a short and easily readable routine, it only does so, if you dispense with parameter checking within that routine and rely on the level above. This is fraught with dangers, especially when, over time, it becomes necessary to add another parameter to the outer layer.

In effect, what I am saying is that I don't mind if individual routines become grow in length, provided each screen sized section of the code is effectively a complete entity. A piece of code with a single, purpose. In this way, it becomes possible to get a good overview of the routine, and still see the detail. Breaking a routine into nested subroutines where there isn't a clear delineation between the subroutine and the calling code, forces the programmer to constantly page back and forth between 2 or more places in the code trying to get a mental grip on what is going on. Even with split screen capable editors, this creates considerable extra work and prevents a good overview. For a while, I used a 'folding editor' (LPEX (Update:corrected acronym)) which allowed you to click on a subroutine name in the calling code, and have it display the body of the subroutine or function in-situ. This was a interesting and powerful concept, and I liked it quite a lot, but it still made it difficult to keep ones bearings when navigating the twists and turns of the code.

This is why I am an advocate of using the largest screen and the smallest font size (commensurate with my aging eye's) that I can. I always found using a large, folding map infinitely preferable to a book of maps for similar reasons. It is inevitable that with the folded (nested) view, the two details of primary interest span a page boundary forcing one to flip back and forth between them rather allowing you to concentrate on the encompassing span in a single view.


Examine what is said, not who speaks.
"Efficiency is intelligent laziness." -David Dunham
"Think for yourself!" - Abigail
Hooray!