Key problem: some comments can’t be expressed through functional decomposition.
I agree that algorithm and data structure explanation should be done largely through functional and OO decomposition and member and type naming, and that this is one of the big reasons why naming is so important, but there are other aspects to programming than call-tree decomposable algorithms and trivially modular data structures. Not all problem domains and corresponding solution abstractions are representable in a first-class way using the tools of structured programming and object-oriented design.
What about global* state changes that affect horizontal sections of code, rather than the vertically-oriented call tree of a functional decomposition?
(* or local to a large object graph - functionally not all that different)
What about concurrent programming, where every cross-thread-visible operation is only correct when every possible relevant state of every other thread has been considered?
What about older programs written in older languages using older techniques - I’m thinking of IDE compilers written in C with extensive global state, discriminated unions and semantic field reuse across different stages, in particular (since it’s my day job). A few comments go a long way in these kinds of situations - particularly since one doesn’t have the luxury of writing it correctly the first time, even presuming that the right abstractions are available in any single programming language.
Code that has been maintained for decades generally doesn’t have an immediately understandable gestalt such that it can be immediately refactored and rewritten more clearly, and in these situations comments are vital to help build up that gestalt, so that future refactorings can occur.
Motivating example: you’ve got a data structure graph that represents a parsed piece of code, and you’ve got to do manipulations, optimizations, debug info extraction, and code generation - and do it all as fast as possible with minimal copying and reallocation etc. Classes don’t sit well with the requirements - you want to separate out your parsing logic, debug info, optimization, code generation, etc., rather than lumping them all into a single class. Each of those phases will want to annotate the graph for its own purposes, but those annotations can go away when the phase is done. You end up using discriminated unions or something similar, along with functional pattern matching or a visitor pattern, etc.
I can assure you that that code (and data structure types) will improve with the addition of a few comments