Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

How should I approach writing comments for callback functions? I want to explain the "why" behind the function when the function and parameter names are insufficient to explain what's going on.

I have always wonder why comments like this can be so ordinary in documents of libraries in dynamic languages:

/**
 * cb: callback    // where's the arguments & effects?
 */
 func foo( cb )

Maybe the common attitude is "you can look into source code on your own after all" which pushes people into leaving minimalist comments like this.

But it seems like there should be a better way to comment callback functions.


I've tried to comment callbacks in Haskell way:

/**
 * cb: Int -> Char
 */
func foo(cb)

And to be fair, it's usually neat enough.

But it gets into trouble when I need to pass some complex structure. The problem being partly due to the lack of type system:

/**
 * cb: Int -> { err: String -> (), success: () -> Char }  // too long...
 */
func foo(cb)

Or I have tried this too:

/**
 * cb: Int -> { err: String -> (),
 *              success: () -> Char }  // better ?
 */
func bar(cb)

The problem is that you may put the structure in somewhere else, but you must give it a name to reference it. But then when you name a structure you're about to use immediately looks so redundant:

// Somewhere else...
// ResultCallback: { err: String -> (), success: () -> Char }

/**
 * cb: Int -> ResultCallback    // better ??
 */
func foo(cb)

And it bothers me if I follow the Java-doc like commenting style since it still seems incomplete. The comments don't tell you anything that you couldn't immediately see from looking at the function.

/**
 * @param cb {Function}  yeah, it's a function, but you told me nothing about it...
 * @param err {Function} where should I put this callback's argument ??
 *                       Not to mention the err's own arguments...
 */
func foo(cb)

These examples are JavaScript like with generic functions and parameter names, but I've encountered similar problems in other dynamic languages which allow complex callbacks.

share|improve this question
14  
Quit picking crappy names for your variables, and you won't need magic comments to tell you what it is... :) –  cHao Sep 17 '13 at 3:33
8  
Here's a wild idea: Write it out in words, instead of weird shorthand syntaxes. –  Zirak Sep 17 '13 at 3:33
1  
@cHao - Be nice. Especially since your words belie your misunderstanding. The OP picked common abbreviations and generic function names to illustrate the point of the question. foo is exceptionally common, and cb stands for "callback" –  GlenH7 Sep 17 '13 at 14:42
4  
@GlenH7: The common abbreviations and generic function names are a big part of the problem here. The name itself is part of the documentation. You don't get to pick some random, nondescript name and then be surprised that it's not documented well. –  cHao Sep 17 '13 at 14:44
    
@cHao: You should post your answer: If the parameter names are insufficient, then rename them. Talk about common sense. I'd +1 that in a heartbeat even if it were worded as you wrote above. –  Thomas Eding Sep 17 '13 at 16:52

2 Answers 2

It depends upon how you're writing your callback functions.

If they're stand-alone functions, then you can use the same commenting methodology that you would use for any other function.

If they're lambda like functions, embedded within other functions, then you start running into problems. You might try to mimic the commenting methods that you would use for a stand-alone function. But by the time you need that level of commenting, you shouldn't be using a lambda function for your callback to begin with.

Lambda functions can be very powerful, but their purpose should be obvious and they shouldn't scroll for page after page.


On a related note, your function names and variables should be descriptive enough to convey what they're doing. For example, use "result" or "results" instead of "callback." Just because you're writing generic / re-usable code doesn't mean you can't use descriptive terms with the parameters.

It's also important not to mix your programming paradigms. Haskell (a functional language) has different idioms than JavaScript. Mixing style is a bad idea and will make your code more difficult to maintain. There's an old programmer's saying of "You can write bad COBOL in any language."

share|improve this answer

The fact that you're providing this example with generic function and parameter names, and then complaining about the lack of documentation, indicates a misunderstanding of the point of names. The name of a thing is itself documentation, and should be descriptive enough to tell you not just the thing's type, but its role as well.

Let's have an example (in JavaScript, cause why not).

/**
 * cb1:             (this Row) ->
 * optional cb2:    (this Row) -> boolean
 */
RowSet.prototype.foo = function(cb1, cb2) {
    if (!cb2) cb2 = function() { return true; }
    for (var i = 0; i < this.length; ++i) {
        if (cb2.call(this[i]))
            cb1.call(this[i]);
    }
}

Even with the doc comment, and even though this is a rather short function, i feel like i'm having to decipher it. It doesn't say anything about semantics, or when it'd be appropriate to use, or any of that.

But if we use non-crappy names for things:

RowSet.prototype.withEachRow = function(rowCallback, rowPredicate) {
    if (!rowPredicate) rowPredicate = function() { return true; };
    for (var i = 0; i < this.length; ++i) {
        if (rowPredicate.call(this[i]))
            rowCallback.call(this[i]);
    }
}

I find the second far more readable, without comments. Once you have decent names, the comments that were all but mandatory on the first example become noise; everything they say can just as easily be learned from reading a couple of lines of code. More reliably, too -- since comments don't affect the functionality of the program, they can say basically anything. It's harder to tell whether someone updated the comments when they changed the function. One would have to read through the function to know that. But wait -- isn't that what the comments were supposed to help us avoid?

What's more, good names become much a more powerful tool the more consistently you use them. For example, when you use the word "predicate" to always-and-only refer to a function that can be called on some item and returns a boolean determing whether that item matches some condition, suddenly it's no longer just a name -- it's a concept, almost a type in itself.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.