Lexical elements: Comments

January 9, 2023

Let’s talk about comments!

This might seem like a pretty dull topic, but there are actually a few nuances in here that even I learned while reading.

Lexical elements


Comments serve as program documentation. There are two forms:

  1. Line comments start with the character sequence // and stop at the end of the line.
  2. General comments start with the character sequence \* and stop with the first subsequent character sequence \*.

Simple enough. We have two comment forms:

// This is "Line comment"

/* This is "General comment */

A comment cannot start inside a rune or string literal, or inside a comment. A general comment containing no newlines acts like a space. Any other comment acts like a newline.

This clarification offers some mildly interesting nuances. Let’s break it down.

A comment cannot start inside a rune or string literal.

Seems pretty straight forward. A rune literal means a rune surrounded by single quotes ('), so this is not a valid comment:

var someRune = '/* invalid comment */x'

And a string literal is similarly intuitive, although there are two forms, which we’ll get into later.

var someString = "/* this is part of the string, not a comment */string"

A comment cannot start … inside a comment.

One might think it’s silly to say a comment cannot start inside a comment, but it actually does have a practical significance to indicate so explicitly, as it means the following examples are not valid:

// A line comment cannot contain the /*  beginning of a general comment
this line is not part of a comment, so would cause a syntax error */
/* You cannot have /* nested */ comments */

The part I find most interesting, however, is the last two sentences:

A general comment containing no newlines acts like a space. Any other comment acts like a newline.

This means it is quite possible to put general comments mid-statement, and it will be valid:

if err /* network error? */ != nil {
  return err

This would be interpreted as:

if err   != nil {
  return err

Which is perfectly valid. Cool.

What doesn’t work, is to include a general comment in the middle of a numeric literal, which one might think since rune and string literals are explicitly called out as invalid.

x := 1/* thousand! */000

Will be interpreted as

x := 1 000

which is invalid.

Although, you can still use general comments between literals and operators, for example:

const foo = 1 /* a comment */ + iota

Of course, there’s still the question whether one ever should do these things. I’m of the opinion that comments (other than GoDoc style comments, which we’ll come to) should be sparse, and we should aim for self-documenting code as much as possible. But that’s quite another topic from what the language allows, of course.

Quotes from The Go Programming Language Specification, Version of June 29, 2022

Share this

Related Content

Empty structs

We finally we have enough knowledge for the EBNF format not to seem completely foreign, so let’s jump back and take a look at that, with the examples provided in the spec… Struct types … StructType = "struct" "{" { FieldDecl ";" } "}" . FieldDecl = (IdentifierList Type | EmbeddedField) [ Tag ] . EmbeddedField = [ "*" ] TypeName [ TypeArgs ] . Tag = string_lit . // An empty struct.

Struct tags

Struct types … A field declaration may be followed by an optional string literal tag, which becomes an attribute for all the fields in the corresponding field declaration. An empty tag string is equivalent to an absent tag. The tags are made visible through a reflection interface and take part in type identity for structs but are otherwise ignored. struct { x, y float64 "" // an empty tag string is like an absent tag name string "any string is permitted as a tag" _ [4]byte "ceci n'est pas un champ de structure" } // A struct corresponding to a TimeStamp protocol buffer.

Struct method promotion

Yesterday we saw an example of struct field promotion. But methods (which we haven’t really discussed yet) can also be promoted. Struct types … Given a struct type S and a named type T, promoted methods are included in the method set of the struct as follows: If S contains an embedded field T, the method sets of S and *S both include promoted methods with receiver T. The method set of *S also includes promoted methods with receiver *T.