Hacker News new | comments | show | ask | jobs | submit login
Block Comments Are a Bad Idea (futhark-lang.org)
48 points by Athas 10 months ago | hide | past | web | favorite | 82 comments

"I don't like something, therefore it is BAD"

I've never had an issue with a block comment that couldn't be fixed in a couple seconds. The usefulness and readability of a well formatted block comment, especially for documentation generation, far outweighs any inconveniences in fixing a broken implementation.

usefulness and readability of a well formatted block comment, especially for documentation generation

it's indeed a bit strange the OP doesn't mention that as an advantage, accoording to the OP the first main purpose is just that it is "perceived that line comments are impractical for long comments"

Line comments are no hindrance to documentation generation. Extracting the contents from a paragraph line comment is a rather simple regular expression[0]. Haskell almost exclusively uses line comments for documentation, and it works fine. You write it like this (the '|' is to indicate that it's a doc-comment):

    -- | Compute this and that.
    -- Parameter @x@ is the good one, and
    -- parameter @y@ is the bad one.
    -- The function works well and runs in time
    -- proportional to $O(n**n**n**n)$.
    f x y = ...

Actually my point was mainly about the readability aspect, should have made that more clear: for me there usually still is a (slight) advantage in readability if every line is not prefixed. E.g. the code you show here looks rather cluttered to me. It doesn't mean it does to you of course, if you are used to it your brain just ignores those dashes. But mine doesn't, since I am not used to it. Though it would probably take me only a couple of days.

Rust supports block comments and line comments; the recommended style is “don’t use block comments”. I have never felt any inclination to use block comments in Rust. These examples of doc comments (using slash-star-star or triple slash instead of slash-star or double slash which are plain comments) are all equivalent, and I know which one I find to be nicest (the third, with line comments):

   * This is documentation.
   * It spans multiple paragraphs.
  pub fn foo() {}

  This is documentation.
  It spans multiple paragraphs.
  pub fn foo() {}

  /// This is documentation.
  /// It spans multiple paragraphs.
  pub fn foo() {}

  #[doc = "This is documentation."]
  #[doc = ""]
  #[doc = "It spans multiple paragraphs."]
  pub fn foo() {}
(You can mix-and-match, too; I’ve combined doc attributes with cfg_attr before, to add doc comments if a certain feature is enabled, see the bonus section in https://chrismorgan.info/blog/rust-cfg_attr.html.)

"I don't have these problems, therefore they are not real problems"

The author makes almost exactly your point regarding the (non)importance of these issues in practice.

What would the author have to write in order to be able to discuss the consequences of this language design choice, and be spared the barb of your wit.

> "I don't have these problems, therefore they are not real problems"

What a major mischaracterization. It was the author that implied things were objectively bad. I stated that the subject is subjective, in that there are use cases where block comments are good.

What the author stated was:

> I will argue that block comments are unnecessary, and in fact near-impossible to design and implement correctly (for my own pedantic notion of correctness)

You might argue, subjectively or objectively, about the utility of the "notion of correctness" used here, but the author warns at the outset that this is the basis for the rest of the analysis.

I ask again, what preface would the author need to write to satisfy your criticism? I think that it's worthwhile for the author to point out that you cannot create a block comment scheme without having some un-intuitive edge cases, and I'm curious what gave you the impression that the author was claiming an unwarranted degree of objectivity.

He argued that future programming languages should get rid of them completely.

Yes, but based on an subjective judgment. I am the author of the blog post, and I tried to do my utmost to emphasize that my judgment here is highly subjective, using phrases such as "for my own pedantic notion of correctness", and "I cannot in good faith claim that [problems with block comments] occur all that often in practice". I try to make it clear that I'm not surprised, offended, or annoyed that most languages support block comments.

How do you think I should have put my words, to make it clear that my opinion here is not intended as objective fact, but merely a subjective take on a language design question?

* Don't state that other people should change years of convention to meet "your pedantic notion of correctness".

* Center your blog post around "why I don't like block comments" and not "why block comments are bad".

You don't have to solve all edge cases for a feature to be useful. At least not all the time.

I, am not too unhappy with the behaviour of C/C++/Java/... - That the block comment will end at the first occurence of " * / ".

If I accidentally close a comment too early (because there already was another block comment inside the code I want to comment), then...

* The syntax highlighting of my IDE will tell me.

* The compiler will tell me.

* I can take it as an opportunity to consider whether this file is too large - That problem should not have happened at all.

This problem does fall under the umbrella of issues that have the obvious solution of "don't do that"

I really appreciate class-level and method/function-level comments, in languages that have a special format for them to assist with generating documentation (e.g. Javadoc, Scaladoc, JSDoc, etc).

A couple of years back, the company that I work for had a series of lunch-n-learns where each presenter did a chapter of Robert Martin's "Clean Code". One of the chapters deals with comments. Not using them as a crutch, and focusing on making the code readable instead.

The presenter, and one of the more influential archs in the room, was excessively dogmatic about it. Everyone ultimately left the meeting with the message that ALL comments (especially BLOCK style comments!) are "a bad code smell" per se. Overnight, everyone in the department all but stopped writing code comments.

Fast forward two years, and now it's a complete and utter nightmare to touch anyone else's code... or even your own code that you haven't seen in awhile!

Now, I understand eschewing the auto-generated blocks that your IDE might throw on the class level (e.g. "Created by John Doe, on 2017-10-11"). I understand not placing Javadocs on getters and setters and other trivial methods. I understand rejecting clutter.

However, for any non-trivial unit of code... you owe it your peers, your successors, your future self who has to maintain this later, and just the gods of professionalism in general, to throw on a brief comment blurb signalling the intent of the class or method/function.

Before starting, I was expecting this piece to be about semantics, not syntax. Something like line comments encouraging concision, where block comments are too large of a canvas.

If I had to distill my criticism about block comments, it would be that my inclination to read someone's multi-line block commented description of the purpose of some variable or loop approaches 0 as number of lines grows past 1, let alone some lengthy TODO blather.

I was reminded of some of the Java best practices, eg. http://www.oracle.com/technetwork/java/javase/documentation/....

It's kind of surprising to me that anyone past junior-level development doesn't already have it hammered into them that "code is how you did something, code is why you did it".

Also, if you can't possibly be any less clever in your code, then leave a comment explaining the "how", and apologize that you couldn't make it any simpler.

s/code is why/comment is why/, I think?

Doh, sorry, you are correct. I can't edit the comment any more, unfortunately.

One can call it BAD too, but I’ve done this several times:

  if (self-describing) {
  else if (self-describing) {
  else /* description */ {

  void myfunc(int a, char *b /* optional */, ...)
Block comments are not only block, but also inline. You cannot end line comment on the same line. (Though it is easy to work around).

As of good/bad: if you don’t like it personally, then don’t use it. If in group, then put that in group style guidelines, because these are required to read and follow anyway, for project to be consistent. To prove something is a bad idea in general is a hard work not worth doing.

Put the comments at the end of the line, introducing line breaks if necessary:

  if (…) {
  } else if (…) {
  } else {  // description

  void myfunc(int a,
              char *b, // optional
I don’t program in C or C++, but when working with the Windows API I appreciate Microsoft’s source-code annotation language which leads to being able to indicate input and output parameters, and optional ones, so that you’d wind up with something like this:

  void myfunc(__in int a, __in_opt char *b, ...)
I don’t know how they’re implemented in MSVC, but I’m guessing they’re just empty #defines.

Sure, I’m aware of these methods; these are obvious. But my preference is to put else-comment that way, because its beauty makes me peaceful and calm when I look at it. At work I’ll do what PM expects, i.e. her/his [motivated] preferences, not mine (if you ask people what they’d like to do, work will be hardly a popular option at all, so no problem, it is consensus between being “busy” and having profit).

The D Programming language has a neat trick to block commenting out code for debugging purposes. Wrapping code in a version(none) {} block will exclude the block from compilation. The code inside the block must still be syntactically valid so it avoids the problem mentioned in the linked post.

The D Programming Language - Conditional Compilation: https://dlang.org/spec/version.html

Ditto for Common Lisp, where conditional compilation (with #+ and #- reader macros) is widely used to comment out s-expressions.

EDIT: I only now noticed it was mentioned in the article. I'll therefore add that the example from the article, of using #+nil, is actually not recommended, because it's technically possible that somebody adds a feature flag called "nil". Therefore, it's preferred to use #+(or) or #-(and) for comments (they're degenerate forms of conditional compilation expressions like #+(or flag1 flag2 flag3)).

It's commonly done in C with a #if 0 / #endif preprocessor macro.

D also supports nesting block comments with /+ +/, which helps when you have example code in your documentation

In what ways is that better than "if(false) { }"?

From linked examples it is clear that version() is allowed outside of functions. Since version() already serves a feature, there is no need to overload the meaning of if().

Rust had an RFC at one point that considered removing (some) block comments, which generated a good argument in their favour (see also the longer comment 5 replies later): https://github.com/rust-lang/rfcs/pull/1373#issuecomment-205...

Essentially it's very annoying (slash slash) for blind programmers (slash slash) if their screen readers (slash slash) keep reading out (slash slash) line comment delimiters (slash slash) during long comments.

This feels more like a deficiency in the screen reader than one in line comments.

I'd argue the editor rather than the reader. Readers can't be too specialised, they have to work with a large variety of programs, so it's not going to know it's looking at code, let alone parsing it, unless the editor tells it. Instead the editor should have an accessible interface that only passes up the comment text to the reader, perhaps annotated with a "comment" role or something.

This is my personal preference, but from experience I prefer languages that don't shun concepts because they're bad programming practice. I can understand if something is difficult to implement or prevents other features from being added, but if a feature is possible, I say add it---it might come in handy sometimes. There's a reason languages like C, C++, Ruby, and Javascript are immensely popular. It's because programmers can use and abuse any nook and cranny of it when needed, because they let you mess with pointers, use goto, redefine language keywords through macros, patch standard libary functions/classes, etc. If programmers want to write bad code, let them write bad code. You can't magically make a bad programmer write good code because of restrictions of the language. I've seen some horribly written Haskell for example, despite how "perfect" the language is designed.

For blocks comments in a functional language though, it might work because many people would come from LISP/Scheme, where block comments were never a thing (I think.)

> LISP/Scheme, where block comments were never a thing (I think.)

Lisp does have block comments,

    #| This is a block comment |#
You can also use feature expressions to effectively comment out code

    (defun foo ...)
The reader will skip over the following sexp if the feature expression isn't true (and `(or)` never is).

Incidentally, Ruby has block comments, but almost nobody knows about them, because they're inherited from Perl. Ruby comments are line comments with #, but you can also use =begin and =end for block comments.

See also GOTO which is a wart 99.9% of the time but really useful for writing e.g. parsers.

Error handling.

In most languages there are better way to do this than goto. Among them - extracting code into smaller functions (yes, state has to passed around) - exceptions (yeah yeah, hate them or love them, but if used in your environment it makes sense not to avoid them) - RAII pattern or handling cleanup, which allows simple return and "automatic" resource handling - etc.

True, in a language like C these don't apply necessarily and goto still has some use -

Parsers (or more generally state machines) and error handling are the two places I've seen that are acceptable. We've managed to complete the list. :)

OCaml actually has correct block comments by his definition (and no line comments). This does lead to the odd fact that you can't have an unterminated string literal in a comment, which usually isn't a problem, but can be surprising.

Does this mean that the following comment would be a syntax error in an OCaml program?

    (* Strings are enclosed by '"'. *)

One thing which isn't mentioned here (which i've encountered before) is when conflict tags from source control get thrown into the middle of block comments, and then committed - which leads to all kinds of headaches. This wouldn't happen with line comments.


> This is perfectly cromulent Haskell.

I'm still impressed whenever someone can correctly use this word to embiggen the subject under discussion.

How would one do inline comments without block comments?

I don't know if Python's triple-quote can be used inline, but otherwise that seems like a good solution. I am not entirely familiar with Python comments, does any of his arguments apply to triple-quotes?

You mean comments in the middle of a line of code? I don't think I've ever done that (and I write a lot of C which would allow it). Seems like a readability nightmare to me, even with proper syntax highlighting.

I guess it could be useful if you want to temporarily debug the middle of a line for debugging purposes but in this case you could just add a line break if blockquote didn't exist.

That being said I don't feel very strongly about this topic, I let emacs handle the commenting for me so I never really have issues with nested comments. Besides commenting comments is probably only useful for temporary debugging.

I do feel strongly about people committing commented/dead code however, it's just distracting and misleading. Nowadays versioning your code is just one `git init` away so nobody should be worried about keeping old dead code "just in case".

Sample code is acceptable however, I like Rust's approach where commented sample code can actually be tested to make sure it's up to date.

Triple-quotes are string literals, not comments. It's just that a string literal at the start of a function, file, or class is a docstring.

I view inline comments as a code smell in most languages; I can’t think off-hand of having seen even one occasion where the code couldn’t be tweaked into another nicer form that didn’t depend on inline comments.

I use them with functions that have too many arguments. It's not always feasible to fix the problem at the source.

damageDealt = calcDamage(weaponType, monsterType, DamageType.FIRE, null /* specialEffectFlags /, false / hasMagicTargeting */ );

It's definitely a code smell, but it's much better than nothing and I'm always glad to see these comments when I come back to the code.

Yeah, that was the closest I could think of. But in Python you’d use keyword arguments, and in JavaScript you’d use objects with named fields in lieu of that, and in Rust you’d commonly try to use struct fields or custom enums for such things (I still want named arguments there).

The extreme in your case would be `hasMagicTargeting = false` and then pass `hasMagicTargeting` instead of `false`.

Yes, that is very well possible.

However, I do not recommend using triple-quotes for comments, as git diff only shows 2 lines with quotes while the actual difference is much bigger.

Commenting and uncommenting blocks in lua:

  commented = 123

  uncommented = 456
Commenting and uncommenting blocks by adding or removing a '-'. Pretty handy for trying stuff out.


lua also allows you to define blocks like [=[ ... ]=] but with arbitrary, matching counts of '=' inside.

Using this style with your comment syntax handles having nested and/or dangling comment delimiters in the body.

It's probably the most comprehensive approach I've used. In practice, I've never actually needed more than one level of nesting or dangling but it's not particularly onerous to the parser to include the arbitrary levels.

Surely the solution is heredocs? You effectively define your own comment closing string at the comment opening point.

Yes, heredocs (or "here-comments", since you want them ignored, not just stored in a string variable) would likely be a solution for all but the most pedantic. The final recourse of the pedant would be to point out that no single closing string would be appropriate in all cases, and you are in principle required to read the code you want to comment out, in order to find a closing string that is not already contained within it.

:.,+n|grep eofstr

I use heredocs for 'commenting out' code in shell scripts a lot. For example:

    : <<- 'NOOP'
In some languages there is a very slight performance impact to doing this, however. Especially in the shell, because it actually has to juggle file descriptors whenever a heredoc or herestring is involved — even if you're directing it into a built-in like `:`. (It only costs a few-dozen microseconds though.)

Also, heredocs are irritating because they usually can't deal with indentation properly. bash and zsh support the `<<-` operator which allows you to indent the closing delimiter, but only if you use tabs. Most other languages require the delimiter to be the first thing on the line, which is tedious and confusing.

Python's triple-quotes seem to solve all of these problems, and they're one of the best things about Python's grammar IMO. I wish every language had that, combined with the ability to treat expressions as statements. It'd be a little ugly in C-like languages, but certainly usable:

    my comment

CSS only has block comments, and they’re eager-closing rather than nested. This makes it approximately impossible to comment out code if you add any explanations for why things are how they are or have any other comments inline, which makes me sad.

It is wonderful how 2 of top-3 formats of the web (css, json) went wrong on developers from the start.

Edit: oh, wait, html comments also suck.

This is one of the signs that we're doing it wrong with programming languages.

We're dealing with text. A program can be expressed in text, actually every piece of information can be converted to text some way or another. The question is if it's the right way to do it. It's not.

I know why we chose text at the time. It doesn't make sense today.

In this case, we should be using a tool that would let us write comments without worrying about delimiters or escaped characters. That's so 20th century.

What are you suggesting? Some kind of "rich text"? Or are you suggesting visual programming?

I was just thinking about some kind of code side-car file format which stores comments/docs separately. You'd then have a vertical split view with code on one side and the linked comments/docs on the other. You could select some code and use that to insert/link comments in the other pane.

I'm not entirely sure if I've ever seen something like this before - maybe as a feature in a specific language, but not as an IDE feature for all languages.

as for using comments to disable code - you probably should have the active code in source control and then you are free to simply delete it.

This solution or simply a switch to temporarily disable some chunk of code should be an easy-to-use part of the editor. The programmer should not be concerned with implementation details (implementation details of the editor/language, not the program being written) like nested comments, indentation, etc.

"Visual programming" seems to have too many meanings. "Rich text" too.

I meant code editors that "know" that you are writing code and make things easier for you. In other words, exactly the opposite to one that prompts absurd debates about if multiline comments are a good or a bad idea.

> make things easier for you

This sounds a lot like "do what I mean." You have to tell the editor in some way that you want to write a block comment or not, and that you want to end it.

My editor does make somethings easier for me - if I start a block comment, it automatically inserts the block comment closing character after my cursor. It does syntax highlighting of the block comments, so it's obvious at a glance where they begin and end. I can declare or remove a bunch of single-line comments by selecting a block of text and hitting a shortcut key, or by creating a multi-line cursor at the start of the lines and adding or deleting the single-line comment characters.

I find it hard to imagine an editor with an interface which is easier and faster than entering simple text, once I'm intimately familiar with the shortcuts used with the editor and the syntax of the language I'm writing in. If one exists or could exist, I'd love to know about it!

I find it hard to imagine an editor with an interface which is easier and faster than entering simple text

So you call "entering simple text" to the automatic managing of comments that you just described? I can't honestly agree with that ;)

I think OP is suggesting something akin to the magical automated dev tools of the 1980s (OOH ITS GRAPHICAL) which never actually came to fruition.

I don't know what you refer to. But anyway, be careful with discarding ideas that didn't work in the 80's. What was unpractical then could be very convenient today.

Edit: actually I'm curious how much time it will take for my gp comment to go from "downvoted eccentricity" to obvious.

More edit: I'm not only thinking in more computing power. We know a little more on usability and user experience now than then.

Like Light Table? In the 80s, it would be unimaginable that you could re-compile and run code with every keystroke, or watch the values of variables updating in real time. The demo (http://lighttable.com/#see) would be inconceivable.

That seems too complex. In the 80's there was TurboPascal, an IDE sold for $50 with step-by-step execution and variable inspection. Compilation was extremely fast.

I dislike doing things with every keystroke. I hate when I start typing something in an IDE and it rushes to underline the word with a disapproving red line.

I will second this from bitter experience.

Was translating a very old Pascal program. My editor didn't have syntax highlighting for it. Spent a couple hours translating a very large function. Wasn't until I finished that I realized it was wrapped in a very large block comment.

That, and most decent editors have a "comment current selection" feature that makes single-line comments easy enough.

Why do you fault multiline comments and not your code editor?

Colors don't feel as robust to me as syntax.

   * color blindness
   * broken syntax above typically throws-off subsequent highlighting
   * touch a lot of embedded stuff where having any kind of editor at all (even without highlighting) is a luxury

Decent editors have lexical highlighting as well as commenting selection; this argument cancels itself out.

Personally I like having two block comment syntaxes to choose from, like Pascal's { } and (* * ); normal comments use { }, while if you want to comment out an entire block of the program and not have the comment terminate early, use (* and * ).

Most of my professional life editing Pascal code was done from command-line editors that didn't have support for commenting the current selection, other than piping the selection through a command like sed. I appreciated being able to narrow down bugs using (* and *).

Commenting out whole sections of code incredibly useful for debugging and rapid prototyping.

Many editors allow you to select the section and line-comment it as a whole.

Even vim has a visual block selection mode. <ctrl-v> at the top of the block, then move down (j or down arrow) to the bottom. That marks the block. Then type the I character (insert in front of cursor), type the comment character, and press <esc>. Once you press <esc>, the inserted comment character action is repeated for the whole block.

Or non-visual block select...V% with cursor on the opening {.

Oh, my

  :vmap <M-/> :s|^|//|<CR>
  :vmap <M-\> :s|^//||<CR>
(writing from memory, may need tuning)

Exactly. In java, block comments are used at the beginning of a class or method for javadoc generation. If I want to comment out big portions of code, I use line-comment thanks to eclipse. With this working practice, the problem does not exist. Never use block comments for commenting out big portions of code.

Equally importantly, block commenting fucks with the editor's ability to comment/uncomment code.

Sounds like he's never heard of here-strings. Or discursive text that includes code.

Clojure nailed this, you can throw a comment in the middle of some nested expression, e.g. when building up React.js forms:

     [:p "hello world"]
     #_ [:pre "this debug block is commented out"]]

This works providing you wanted exactly one expression commented out. It's useful, but it's not perfect.

I like how Lua handles the problem, with multi-level open and close comment strings (and string strings). From Programming in Lua [1]:

> A comment starts anywhere with a double hyphen (--) and runs until the end of the line. Lua also offers block comments, which start with --[[ and run until the corresponding ]]. A common trick, when we want to comment out a piece of code, is to write the following:

    print(10)         -- no action (comment)
> Now, if we add a single hyphen to the first line, the code is in again:

    print(10)         --> 10
> In the first example, the -- in the last line is still inside the block comment. In the second example, the sequence ---[[ does not start a block comment; so, the print is outside comments. In this case, the last line becomes an independent comment, as it starts with --.

Furthermore, the pairs of so-called long brackets ([[ and ]], which match the syntax used to declare multi-line string literals) prefixed with hyphens can be converted to 'level-n' long brackets by inserting an arbitrary number of '=' signs between them:

    local commentDescribingString = 
    [===[Lua allows for multiple comment syntaxes.
    You can use two hyphens: '--' for single-line comments.
    Opening 'long brackets' with these hyphens (--[[) start block comments.
    Long brackets can contain '=' signs to form different bracket pairs.
    Closing long brackets must match the number of '=' signs, and do not
    require the hyphens (but they look better and are more convenient)
    These would be comments if they weren't in a string literal:
        --[[ Level 0
        --[=[ Level 1
        --[==[ Level 2
        print("this is really thoroughly commented out.")  -- It is!
        --]==]   -- Closed level 2
        --]=]    -- Closed level 1
        ]]       -- Closed level 0 without the hyphens
    I had to use level-3 long brackets to declare this string.

    print(commentDescribingString)  -- Prints above paragraph
Single-line comments go to the end of the line, of course, no matter how many hyphens there are. Single-line strings can be declared with any number of single- or double-quotes:

    local singleLineString = """This string with 'single', ''double single'', ""double"", or ""double double"" quoted words might be hard to write in other languages!"""
Of course, there's also 'if (false) then (block of code) end' as in every language. The code still goes through the parser, so it takes compilation time if not execution time, and you can have scope conflicts, but that's OK IMO. Surrounding it in an 'if (false)' block is one quick step away from changing 'false' to 'true' to re-enable it, or changing 'false' to a variable to make it optional, which is nice.

>local singleLineString = """...

Is it new syntax of 5.3?

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact