Small Function Headers

As opposed to MassiveFunctionHeaders.

An example of a small function header:

 //////////////
 // This function trims right and left of the string
 //////////////
 function trim(s)
 {
	....
 }
If you want to add comment for parameters, you can add extra lines, starting with //.

This way, you don't waste space for useless function/method header, but at the same time while fast scrolling down the code, your eyes can catch separations between functions. -- SavasAlparslan

What's with the useless tear lines? Why not just write

 // This function trims right and left of the string
 function trim(s)
of course, it doesn't say what it trims... (more realistically it would read function trim( string s ))

Why not drop the header altogether? You don't need to document that this is a function, that is apparent. If the trim right and left information is what is important, rename the function to something like trimLeftAndRight() or extractMiddle(). The function name should be self-explanatory and not need a definition where the caller is not likely to see it. -- WayneMack

little note: "useless tear lines" are just for catching the beginning of a function while fast scrolling the source code. -- SavasAlparslan

I find that as my functions get shorter and more numerous, the tear lines just get in the way. Assuming you left justify the function name and indent the function body, the tear line visual clue is already there. -- WayneMack

SyntaxHighlighting can also do a good job of delineating function boundaries. Most editors will highlight the function defining words, so functions immediately stand out. This doesn't require visual space or typing, and stands out even more than comments (which are also usually colored). -- JonathanTang


Function headers are not evil or wrong. They're just a sign that the code may not be clear enough. -- WayneConrad


An approach presented to me by a previous co-worker:

 // -----------------
 // function trimSides
 // input: theString = string
 // returns: middle portion of theString, using the Wiki2001StringAlgorithmNotByKnuth
 // assumptions: theString must be at least 3 characters long (plus terminating null)
 //  to avoid buffer overflow error.  NotKnuthStringLibrary must be opened & initialized 
 //  before calling this function.
 // ------------------
 function trimSides(char* theString) {

The key addition here is defining the ASSUMPTIONS or RUNTIME REQUIREMENTS that are not obvious from the code itself as well as relevant references.


Why not make those assumtions and runtime requirements obvious from the code instead? You could either use asserts or you could check for the relevant conditions directly and throw an appropriate exception if they are violated.

 void trim(String theString) {
	assert theString != null;
	assert theString.length >= 2;
	assert NotKnuthStringLibrary.isInitialized();
	...
-- FalkBruegmann (hoping to work in a language with full support for DBC one day)

Great idea, Falk! Unfortunately the language selected by the GoldOwner does not support assertions, so the comments were needed to explain what can't be put in the code. See someone else's hypothetical reasons below.

Would rolling your own assertions help? In the simplest case, its just a couple of static methods in some utility class, after all. Restrictions are, such preconditions are not inherited (Java doesn't do this either), and you have to care about switching them on/off yourself. -- fb

Response:
  1. The NotKnuthStringLibrary? was very cleverly named "k2104b" by its creator, and we don't have the source. So we can't call it the "NotKnuthStringLibrary?" without comments or some hack.
  2. The library doesn't support an 'isInitialized()' function. Its behavior is simply "undefined" if you fail to follow the protocol.
  3. What about the "Wiki2001StringAlgorithmNotByKnuth" algorithm comment?
  4. True, a more descriptive function name would probably be helpful -- like trimLeadingAndTrailingSpaces maybe.

This response 1-3 doesn't obviate the need for SmallFunctionHeaders in the normative case. Only in the abnormal cases where you are left hanging.

Possible solution for 1.: Write a wrapper class / layer for k2104b with an Interface suitable to your needs, including isInitialized; alternatively, put the isInitialized logic into your own class responsible for initialization, and check it there (ForeignMethod). May not be worth the trouble, though.

Ad 3.: Right, which specific algorithm is used should not be part of the contract. If you are interested in specific properties of that algorithm, would it be possible to put those into preconditions?

BTW, I'm not criticizing SmallFunctionHeaders - just trying to get them even smaller ;-) -- FalkBruegmann


My favorite example of header comment reduction is in ObjectOrientedSoftwareConstruction 2. The example starts life as ...

  tangent_from (p: POINT): LINE is
           -- Return the tangent line to the current circle going through the point p,
           -- if the point is outside the current circle.
     require
        outside_circle: not has(p)
Meyer relentlessly removes the cruft from the comment.

The streamlined version of the function is now ...

  tangent_from (p: POINT): LINE is
           -- Tangent from p
     require
        outside_circle: not has(p)
Given that the comment merely repeats the name of the function, I'm surprized he left the comment in at all.

tangent_from (point_on_circle: POINT): LINE is -- mainly because I view single letter variables as a CodeSmell, with the possible exception of loops (and that is due to programmer familiarity). And I agree, the comment no longer has any value, although perhaps it is an intentional way of drawing that fact to the readers attention.

Interesting that the previous paragraph shows that it's author didn't understand either the original comment or the code (which both said that the point p is 'outside' the circle, rather than 'on' it). That shows how right his approach was: he would probably not have misunderstood.

 tangent_from (point_outside_circle: POINT): LINE is
Of course, that may just be that non-eiffelers are not used to looking for the 'require' element as part of the signature of a method.

For any circle and point not on the circle, there are 2 (two), not 1, possible LINEs which are tangent to the circle and pass through the point. Which does the function return?


Can't we just generate JavaDoc comments from code?

Assuming you are using JavaLanguage

JavaDoc works for many other languages with similar syntax to JavaLanguage. I've seen it used to good effect with PHP. I suspect it'd also work with CeeLanguage/CeePlusPlus and other C-syntaxed languages. -- JonathanTang

EditText of this page (last edited July 6, 2006)
FindPage by searching (or browse LikePages or take a VisualTour)