Almost all languages have comments, but the syntax for comments can vary wildly between them. What are commonly used options for comment syntax, and what are their advantages and disadvantages?
14 Answers
Comments generally fall into two flavors: single line comments, which end with a newline, and comments with multi-line support, which typically end with the reverse of the opening token or something similar.
For the former, some of the most common opening tokens are //
(Java, C, C++, C#, Rust, etc.), #
(Python, Perl, Ruby, various Unix shell languages, etc.) and %
(LaTeX, etc.); for the latter, /*
(at least for languages inspired by C). Some languages use special exportable (think documentation) comments when the last symbol is repeated (e.g. ///
for C# and Rust, /**
for Java).
A disadvantage of the implementation of multi-line comments in many current languages is that they can't be nested. If you commented out a small part of your code by surrounding it with /*
and */
, and want to comment out a larger part which includes the smaller part, that requires some extra attention, because the end token of the inner comment will also finish the outermost one. Still, your language may be able to solve that by requiring a */
for every /*
(or equivalently, interpret every /*
as starting a new comment, even if it's within another one, and require it to be properly terminated).
-
3$\begingroup$ Some languages do handle nested
/* */
comments properly. T-SQL is one example. $\endgroup$– DLoscCommented May 19, 2023 at 17:15 -
1$\begingroup$ Scala also handles nested
/* */
comments properly. There's other styles of nested multiline comments too:#[ ]#
(Nim),{- -}
(Haskell),(* *)
(OCaml), and probably plenty others. OCaml in particular is interesting because it forces comments to contain only valid lexical tokens (no unterminated strings and stuff). I think this is to help with the nesting, but I'm not sure $\endgroup$– userCommented May 19, 2023 at 17:20 -
$\begingroup$ Matlab block comment:
%{ %}
, but iirc the open and close comment markers need to be on their own lines. $\endgroup$– Bbrk24Commented May 19, 2023 at 17:21 -
8$\begingroup$ Worth noting that
#
is kind of "special", since it lets you use#!
in your language without any extra help, which is probably part of the reason it's so common for scripting languages. $\endgroup$ Commented Jul 5, 2023 at 17:40 -
3$\begingroup$ @user: Yeah, OCaml doesn’t require that nestable block comments’ contents be lexically valid overall, but straight quotes do need to be paired. So you can’t write
(* London Latitude: 51°30'35" N *)
. It means OCaml doesn’t suffer from the corner case in, say, Haskell, where{- a comment ends with "-}" even in quotes -}
. OCaml’s compromise lets you use block comments both for temporarily disabling code, and for writing documentation that contains code, at the cost of a different, maybe slightly less pointy corner case. $\endgroup$ Commented Jul 5, 2023 at 18:09
Using the line ending character ;
as a comment marker
In many assembly languages, the ;
, which also marks the end of a statement, also marks the rest of the line a comment, eg:
MOV aex abx ; move the value to the other register
ADD aex 2 ; add 2
SUB dex mix ; I don't think these are even real registers
BNEQ ; branch not equals
This is nice since you need one less syntax element
-
4$\begingroup$ I don't think I've ever used the semicolon as a line ender in assembly, only as a comment starter. Is there an assembly dialect where this is required as a line terminator? $\endgroup$ Commented May 19, 2023 at 17:33
-
1$\begingroup$ @SilvioMayolo D's Inline Assembler does require it, and uses
//
,/*
,/+
and friends for comments, to be syntactically compatible with higher-level D. $\endgroup$– LonginusCommented Oct 14, 2023 at 17:38 -
$\begingroup$ I wonder if this is what inspired the Lisp designers to use
;
as its comment prefix. $\endgroup$– BarmarCommented Oct 20, 2023 at 16:01 -
1$\begingroup$ @Barmar Yes, it was. Maclisp borrowed the notation from PDP-10 assembly. $\endgroup$ Commented Nov 30, 2023 at 23:01
Comments by way of an identity function
A unique type of comments is through the availability of an infix operator which returns one of its arguments, e.g. ⊢
in APL which returns its right argument. This allows comments as strings inside expressions:
2+'comment'⊢5×8
42
-
$\begingroup$ Could this be emulated in C or C++ by exploiting the comma operator? $\endgroup$ Commented Oct 14, 2023 at 22:59
-
1$\begingroup$ @KarlKnechtel: It appears that is possible, such as
printf("%d\n", ("number",5));
. However, I would say "abusing" instead of "exploiting", and honestly I've never seen a comment written that way in any C language family code. $\endgroup$ Commented Oct 15, 2023 at 23:20
Words
Batch and BASIC allow you to use REM
for comments (although Batch also has ::
and some implementations of BASIC also have '
(see comment by Steffan below)). J has NB.
. I'd recommend against using words for comments, though, it keeps people from using useful identifiers and it just looks verbose and weird.
-
1$\begingroup$ BASIC also uses
REM
, but it's aliased as'
in some implementations $\endgroup$– naffetSCommented May 19, 2023 at 17:26 -
2$\begingroup$ The REM is for REMOVE. This it could be implemented as an operator or otherwise a keyword in the language. Makes sense in something like a shell script (batch files) where lines can be commands anyway
cd temp
ormove from to
are all series of words that start with the command then the parameters. And the parameters can be just arbitrary amount of parameterstouch one two three four
for example. Thus arem
command can just be a simple no-op - takes any amount of "parameters" that can be strings and numbers but does not do anything at all. $\endgroup$– VLAZCommented May 19, 2023 at 18:26 -
7$\begingroup$ I alwaus thought REM stood for "remark", as a synonym for comment $\endgroup$– abel1502Commented May 20, 2023 at 22:44
-
1$\begingroup$ @abel1502 that REM stood for remark has always been my understanding also, since learning COMAL80 - a Danish structured BASIC with strong influence from Pascal and Algol 68 - in 1982. COMAL itself iirc supported both REM and // as line comment. $\endgroup$– LHPCommented May 21, 2023 at 8:32
Slashdash Comments
Along with single line and multi-line comments, the document language KDL supports a novel, scope/syntax aware form of comment syntax called "slashdash" comments. In KDL, the token /-
will treat the following node, argument, property or children block as a comment, even if it spreads across multiple lines.
In this example, the argument "commented"
, the property key="value"
, and the children block { a; b }
are commented out.
mynode /-"commented" "not commented" /-key="value" /-{
a
b
}
Application of this comment style will obviously somewhat depend on consistency in the language grammar. For example, this could readily be applied to S-expression syntax.
; the arguments `3` and `(/ 1 0)` are commented out
(+ 1 2 /- 3 4 /- (/ 1 0)) ; yields 1 + 2 + 4 = 7
Brent Roose in this blog post suggests (AFAICT) a /--
variant that comments out an entire scope of code for use in less homogeneous languages.
// `final` and `implements Bar` are commented out
/-final class Foo /-implements Bar {
...
}
// The entire declaration of `Foo` is commented out
/--final class Foo implements Bar {
...
}
Slashdash comments can be an easier and more elegant way of commenting out code. However, it might not be immediately clear what is being commented out. Also, being fairly unknown, it will require some time to explain to users before the concept clicks.
-
$\begingroup$ Racket does something similar, I believe the notation is
#;
but I may be misremembering $\endgroup$ Commented Jul 5, 2023 at 17:39
It shouldn't be difficult to list the major comment conventions in use or used in the past. Going back to punch card times, there is the '*' in column 7 for COBOL.
FORTRAN had (has?) a similar convention '*' (or 'C', 'c', 'd', 'D' or '!'?) in column 1 to make a comment line.
Many assembler languages, and I believe also (early?) LISP regard a semicolon and anything following it, until line break, as a comment.
This "remainder-of-line" comment style is also used in BASIC, either with a keyword "REM", or sometimes a single quote, and in Unix shells and Perl, where the character is '#'.
Non-line oriented (free form) languages, probably beginning with Algol, need a delimiter in both ends. In Algol 60 a comment begins with comment and extends to the following ';'. As only another end or a ';' can follow an end of a block, any text after end, up to a ';' (or another end?) is also considered a comment. Obviously this may lead to errors. Algol68 introduced comments beginning and ending with the comment symbol, often written as a '¢', but sometimes also '#'. Pascal uses '{' and '}' (or '(' and ')' when the character set does not have curly braces. Originally they didn't nest, but I think some implementations and perhaps recent standards allow comments to nest.
PL/1 uses '/*' and '*/', which was also used by C. (I believe BCPL and B had remainder-of-line comments?) C++ reintroduced '//' remainder-of-line comments. Both types are common in C-inspired languages.
Ada, SQL, SGML (and XML?), ASN.1 and maybe a few more use '--' , I think at least one of them allows another '--' on the same line to end the comment, allowing a comment inside a statement, others use it for remainder-of-line.
Some consider the nesting of comments to be a feature, because it allows commented code to be "commented out". With "modern" (ie decades old) version control, this argument seems somewhat dated to me.
One problem with comment delimiters is that they may conflict with the plain syntax. In C for example 'x/ *divp' is a valid division expression with the divisor being a dereferenced pointer, but if the space is removed, a comment would be expected instead. This is of course not a problem in PL/1 and Pascal, where '*' is not a prefix operator. The same applies to '--' with unary '-', although a binary or unary '-' followed by unary '-' is probably not really needed in any code.
"Literate programming" turns the idea of comments upside-down (or inside-out), as the main text is "comment", with code interspersed. Perl has POD section comments, beginning with a '=pod' line and ending with '=cut', which contain POD markup text, used by Perl documentation tools. Python implements something similar with docstrings, and Java uses Javadoc annotations (although embedded in "normal" comments) for a similar purpose.
All the comment styles above share one major disadvantage: they might lie! As they normally allow free, uninterpreted text, there is no way to ensure that the content of a comment is true or meaningful. Sometimes code gets revised without updating the comment. And sometimes comments are just not very useful, like comments that just repeat in words what a statement does.
Some languages therefore have more useful types of "comment", in the shape of assertions and pre/postconditions. Bertrand Meyer's Eiffel was probably an early example of taking this to the extreme, with require, ensure, and loop and class invariants. I think this is based or Hoare logic, where the notation {P}S{Q} (with P, Q being predicates expressing pre and postconditions for the statement S) is used. I guess Pascal may have taken its comment delimiters from this (but without semantic significance.) Other languages have some form of 'assert' statement.
One thing that made a big impression on me in my second year of CS, was the notion of "auxiliary variables" introduced by Susan Owicki and David Gries in their paper on conditional critical regions. Auxiliary variables may be assigned from (side-effect free) expressions, but may not themselves be assigned to non-auxiliary variables. Therefore all assignments to aux vars may be deleted without changing the meaning of a program. However, the aux variables may be useful in assertions, pre- and postconditions and other ways for proving correctness of the program.
I guess this is the point where comments cross over and become more expressive forms of programming with declarative programming styles and type systems at the same time being "comments" about the code, and the code itself.
If I should describe the form of comments I would like to use, it would be a combination of free-form text, with code embedded using indentation (ie unindented lines are comments, indented lines are code), and Hoare Logic notation, with all Boolean expressions occuring in "void context" being seen as assertions. Likewise, string expressions (with formatted interpolations) in "void context" would either be ignored or taken as debug print statements.
Double Slash, Single Line // Comments
This is what languages such as Java use, in addition to multi-line comments. The comment ends at the end of the line and any text immediately after the //
will be ignored.
This comment is useful for quick, one line explanations of a certain piece of code. They can easily be placed next to or immediately above a small line of code to show that the comment explains that one line.
As a simplistic example:
// Declares a variable 'a' with the value 100
var a = 100;
var b = a * 10; // Declares a variable 'b' with the value 1000
However, one disadvantage with this syntax, which is true of single line comments as a whole, is that is harder to comment out entire sections of code you want to ignore. Each line must be individually commented out.
This becomes tedious and generally very messy visually.
// Ignored code
// for (int i = 0; i < 10; i++) {
// System.out.println(i);
// }
-
4$\begingroup$ Commenting out individual lines is less of a problem in IDEs that have a keyboard shortcut for it (often Ctrl-/). $\endgroup$– Bbrk24Commented May 19, 2023 at 17:23
Strings as comments
This is often seen in Python (see "Python multi-line string" and "Python tripple quoted string").
With this, programmers can simply use a string as a comment. For example,
"""
Some text here
Some more text
Even more text
"""
print("""Hello world""")
This can be nice as separate syntax isn't needed (though Python has real comments too), but with the trade-off that it might be considered (ab)using a feature. In the case of Python specifically, this is specifically documented in PEP 257, so it isn't really abuse there.
-
1$\begingroup$ @user16217248 How would this degrade performance? The strings would just be initialized and then left untouched for the rest of execution, right? $\endgroup$– GingerCommented May 19, 2023 at 19:39
-
3$\begingroup$ @user16217248 Is the performance loss actually measurable, though? Worrying about that feels like worrying that one day a tree will grow where I'm standing. $\endgroup$– GingerCommented May 19, 2023 at 20:05
-
4$\begingroup$ A string that is not assigned to anything - or any constant expression in "void context" for that matter - would be trivial to compile into nothing at all. No performance hit whatsoever. One (minor) disadvantage would be that such a comment can't easily be placed inside an expression. Also, in a language with a statement terminator or separator (typically semicolon), it might look a little awkward. $\endgroup$– LHPCommented May 20, 2023 at 20:23
-
5$\begingroup$ Note that docstrings are not comments. They are syntactic sugar for assigning to an attribute named
__doc__
. The whole point of docstrings is that, unlike comments, they are not ignored but kept around at runtime so you can query them at runtime. $\endgroup$ Commented Jul 5, 2023 at 11:16 -
1$\begingroup$ This doesn't degrade performance at all, at least beyond the cost of parsing the string literal (which is one-off and negligible, possibly not even more expensive than parsing a comment beginning with
#
). CPython absolutely recognises a string literal on its own as a noop and doesn't emit any bytecode instructions for it. $\endgroup$– kaya3Commented Oct 14, 2023 at 16:18
I'm surprised that Lua hasn't been discussed:
-- Singleline
--[[
Multiline with delimiters.
]]
--[=[
[[Delimiters]]
]=]
--[==[
[[can be]] [=[arbitrarily long]=].
]==]
These delimiters are called opening and closing long brackets. The comment nesting problem mentioned by other answers can be easily avoided by increasing the level of the long brackets, as shown in the example above.
What's more, these brackets are also used to delimit (multiline) string literals:
local s = [=[
Foo[[bar]]baz[==[qux]==]
]=]
The /* */
notation
This is what CSS uses.
Example:
/* Some text */
This method has a number of advantages:
- Due to it not automatically going to the end of the line (it stops at
*/
), it can be midway-through a line - It can span several lines if needed:
/* Some test
Some other information
Even more stuff
*/
-
4$\begingroup$ Not just CSS ─ this comment syntax exists in C, C++, C#, Java, Javascript, PHP, and many more languages. Particularly languages which borrow their syntax from C tend to have this kind of comment. $\endgroup$– kaya3Commented May 20, 2023 at 3:18
If you use either # or #! as a comment starter, then your file can run directly on Unix via a so-called Shebang. That is, on Unix, a file starting with #!
(path) will run the file as code under the interpreter at (path). If # or #! is a comment, the interpreter will then skip over the shebang line and all is well
Of course, if you prefer alternative syntax for comments, you could still include a special case for skipping a shebang
-
$\begingroup$ This is very annoying in ECMAScript. Hashbangs only became legal with the June 2023 release. $\endgroup$ Commented Jul 5, 2023 at 11:09
-
1$\begingroup$ @JörgWMittag I'll note that it was supported by Node for much longer, even if it wasn't part of the standard. $\endgroup$– Bbrk24Commented Jul 5, 2023 at 14:46
Newspeak has nested metadata which looks like this:
(*:id: xyz *)
This associates the metadata payload xyz
under the metadata tag id
with whatever runtime language element follows the metadata comment. This information is kept both in the compiled code and at runtime and can be queried using reflective mirrors. The metadata tag identifies a specific metadata interpreter. (This is, for example, how Newspeak does its optional type annotations.)
In other words, these are similar to Java-style annotations, C#-/.NET-style attributes, C++-style attributes, but also have aspects of Python- and ECMAScript-style decorators.
Metadata can nest, i.e. I can annotate metadata with metadata.
Comments are simply metadata without a tag:
(* This is a comment (* And this is another, which comments on the outer comment *) *)
Since they are still metadata, they are attached to the runtime language element which follows them. And this applies to nested comments as well, so the above inner comment is a comment attached to the outer comment.
Since they are attached to actual runtime language elements, it is easy to keep them around and reconstruct them even through large-scale complex automated refactorings. You can do cool stuff like: when catching an ArgumentError
, retrieve the documentation comment for the method which raised the exception and show it together with the stack trace. Since the comment is an actual object attached to the actual method object, you can literally just grab it from the stack trace object.
Python-style comments
#
starts a single-line comment. It's only one character, so it's quick and easy to type."""
or'''
delimit multi-line comments. These are actually "docstrings", but they can also be used as comments. They are three characters on each side, so it's a bit longer to type. They are also ambiguous, since they can also be used for multi-line strings.
Examples:
# comment
"""multi
line
comment"""
'''
this as well
'''
-
1$\begingroup$ Note that docstrings are not comments. They are syntactic sugar for assigning to an attribute named
__doc__
. The whole point of docstrings is that, unlike comments, they are not ignored but kept around at runtime so you can query them at runtime. $\endgroup$ Commented Jul 5, 2023 at 11:17 -
$\begingroup$ @JörgWMittag I know, but they are essentially used as multi-line comments $\endgroup$ Commented Jul 5, 2023 at 14:48
-
$\begingroup$
'''
and"""
enclose multiline string literals. Docstrings in Python are simply when any string literal forms the first statement of a module, class or function. $\endgroup$– JasmijnCommented Dec 19, 2023 at 15:47
The choice of comments should come down to basically one thing: What language or family of languages are you emulating?
C and its enormous family of languages generally use //
for single line comments and /* */
for block comments. I would recommend this style of comments because they are the most widespread. They'll also let you play with JavaDoc documentation, which is usually implemented as /** */
or ///
in some cases.
The other most common style of comment is to use #
. This is usually found in older languages like ShellScript and languages that borrow from them like Python. Most of this languages only support single line comments, however, so this style of comments may feel slightly limited. You could maybe implement your own block comments by using ###
or any combination of characters that you fancy.
I wouldn't recommend using outlandish comment syntaxes just to keep the language approachable.
P.S.:
I'll give XML and its many children a mention for only having block comments (denoted with <!-- -->
). Having only block comments might be something interesting to try out in a more esoteric language.
-
$\begingroup$ Technically speaking,
<!
is the start of a directive and>
is the end of a directive.--
is a comment toggle, meaning it toggles between comment and non-comment mode. This means that<!-- This is a comment--I think -->
does not do what you expect! $\endgroup$ Commented Jan 12 at 11:51