Yeah, this is pretty obviously true when you consider how limited our human brains are: we just can't keep all that information in our heads at once, and so since comments aren't critical for actually running the program, it makes sense to filter them out mentally.
For me personally, I normally never write comments. When I do, it's only for three reasons:
---
1) To provide a reminder for things that need to be fixed later. These always contain "TODO" at the front, like this:
// TODO: replace foo with bar
I use a lot of these. I find it's a lot better than keeping a separate TODO list. Unit tests would work too, but I've gotten into the bad(?) habit of using unit tests sparingly, only for tricky corner cases, rather than having full code coverage.
---
2) If I'm writing a library that I expect other people to use/modify/whatever, I'll comment anything that I consider to be really important for using the library.
For instance, in the Pratt parser that I wrote last night (in JavaScript), I used comments like this:
// Converts any array-like object into an iterator
// <n.expression>, <n.parse>, and <n.parse1> all expect an iterator
// Expects an iterator of tokens and an optional priority
// Parses tokens until it finds one whose priority is lower than or equal to <i>
// Returns the parsed expression
// Expects an iterator of tokens
// Returns a list of all the parsed expressions in the iterator
// Creates a token that throws an error when used
// This is useful for placeholder tokens, like the ending pair of braces
// Creates tokens for braces
// Example usage:
//
// var t = new PARSE.Tokens()
// t.braces("(", ")")
// t.braces("[", "]")
// t.braces("{", "}")
//
I tried to keep them as short as I could, and only included the information people needed to know, like how to actually use the library, rather than providing in detail how the algorithm works. The code should be simple enough that you can study it to see the algorithm, so the comments are detailing high-level stuff.
And I especially tried to only give examples of usage when necessary, because examples take up a lot of space. So my commenting philosophy seems to lean toward "don't comment unless it's important, and try to keep comments as short as you can".
---
3) If I'm writing internal code that only I use, I'll very rarely put in a comment that explains something tricky:
// This is needed because of foobarqux
But this is quite rare because only I see these comments, so the only time I put them in is if the code is so complicated that even I can't understand it.
Because most of the code I write is in Arc/Racket and is for my own use, the only comments I write are of type #1, and very rarely type #3.
---
So my commenting philosophy is flexible: when I expect other people to use something, I'll provide a high-level comment explaining how to use it. But if it's just internal stuff that only I use, there's no need to provide comments.