Language Idioms Encouraging Small Methods

In some languages there are commonly used idioms that encourage refactoring into small modules -- quite independently of any formal refactoring or ExtremeProgramming influence.

Consider...


ForthLanguage:

Forth has a very low subroutine-call overhead, as there is no need for "stack frames" or other mechanisms used by other languages to support local variables. And Forth's lack of complicated syntax and lack of need for type declarations makes it trivial for programmers to create additional subroutines. So Forth encourages breaking up a program into lots of very small subroutines (called "words" in Forth). This leads to some interesting idioms for flow-of-control.

Also, Forth functions/subroutines have no formal parameters (they pop and push values to the stack), so the body of each function is just a list of function names to call. This syntax lends itself to terseness.

ChuckMoore, designer of ColorForth, recommends that instead of using "if...else..then", "if" statements should be moved into their own words and use a syntax like that of a GuardClause. In "ElseConsideredSmelly," this ColorForth example was given:

 doCondition  condition if ifBlock ; then elseBlock ;
translated to "C" as...
 void doCondition() {
   if (condition()) {
     ifBlock();
     return;
   }
     elseBlock();
 }
In ANS Forth, this would be

 : doCondition  condition if ifBlock exit then elseBlock ;

[Also, tail-recursion for loops]

ChuckMoore also favors using tail-recursion for loops (although he also uses BEGIN..END and FOR..NEXT), such as in this ColorForth example:

 doLoop  condition if loopBody doLoop then ;  \ call loopBody while condition true
translated to "C":
 void doLoop () {
   if (condition()) {
     loopBody();
     doLoop();
   }
 }
In ANS Forth, this would be

 : doLoop  condition if loopBody recurse exit then ;

[Also, no function larger than a page]

My FORTH knowledge is quite dated, but at least in old versions of FORTH (early '80s)...

Code is written in and loaded from logical disk pages. (1K page = 16 lines of 64 characters?) Function definitions can't span pages, so the question of "is a function that doesn't fit on a page too large" is moot: You can't do it; the syntax that the loader recognizes doesn't allow it.

So, if you find yourself (#1) moving the function's definition to its own page and then (#2) cramming lots of code on each line and then (#3) looking at the comments to see if you could make more room. Then somewhere around #2, you should realize that your function is clearly excessively too long.

I suppose that one could change the loader to recognize multi-page functions. But by the time you'd know enough FORTH to do this, you'd know enough FORTH to not want to.


LISP:

When I learned LISP (which was many moons ago) the syntax for conventional procedural looping was ackword, but tail recursion very well supported and optimized. (...or maybe this was just a conspiracy of college instructors! ;-) Anyway, using recursion for looping was much easier and more "natural."

But if you do all looping with recursion, then the "body" of every loop must be moved into a separate function.

The SchemeLanguage standard requires that implementations support ProperTailCalls. The CommonLisp standard does not require implementations to be tail-recursive, although many implementations provide it anyway. For true iteration, Common Lisp has, among other things, the loop macro:

 ;; An example of the extended form of LOOP.
  (defun square-advisor ()
    (loop as n = (progn (format t "~&Number: ")
                        (parse-integer (read-line) :junk-allowed t))
          while n
          do (format t "~&The square of ~D is ~D.~%" n (* n n))))
 =>  SQUARE-ADVISOR
  (square-advisor)
 >>  Number: 4<NEWLINE>
 >>  The square of 4 is 16.
 >>  Number: 23<NEWLINE>
 >>  The square of 23 is 529.
 >>  Number: done<NEWLINE>
 =>  NIL

--SethGordon


COBOL (before COBOL'95):

Aside from GOTO's, COBOLs native support for looping is provided with modifiers on the "PERFORM" verb -- like "PERFORM EMPLOYEE-PROCESSING UNTIL END-OF-EMPLOYEE-FILE." This means that the body of each loop must be pushed out into a separate paragraph, limiting the size and complexity of the code you could find in any one paragraph.

COBOL-85 "fixed" this problem with in-line perform statements: You can now say "PERFORM UNTIL END-OF-EMPLOYEE-FILE <lots and lots of code here -- in the same paragraph> END-PERFORM."

[Also (before COBOL-85) lack of END-IF limited code complexity]

COBOL doesn't have begin/end or "{...}" blocks. So writing complex nested IF statements can be a trick. Sure you can do "ELSE CONTINUE" ("CONTINUE" is a null statement; it doesn't do anything), but the need to do that pretty clearly shows that the code is a mess.

COBOL-85 "fixed" this problem with "IF ... ELSE ... END-IF" syntax. Now you can have unlimited complexity in a single COBOL "sentence," and not worry about it.

SmallMethods? in COBOL?! Boy, the code you are talking about must have been different from the COBOL code I have seen... ;-)


CategoryIdiom


EditText of this page (last edited December 16, 2003) or FindPage with title or text search