Associative commentary follow up

This post is a follow up to Friday’s post on comments in Go.

Keith Rarick and Nate Finch pointed out that I had neglected to include two important practical use cases.

Build tags

I’ve previously written about how to use // +build tags to perform conditional compilation. In light of the previous post it’s probably worth recapping them here.

  • Build tags must use the // form.
    // +build right
    /* +build wrong */
  • Build tags must be their own comment, they must not be associated with a declaration.
    // Copyright Microsoft 1981
    
    // +build !darwin
    
    // Package basic implements Dartmouth's BASIC interpreter.  
    package basic
  • Build tags must occur early in the file. Only the first few lines of the file are scanned when filtering files by build tags.
    package wrong
    
    import "io"
    
    // +build whoops too,late

Copyright headers

The second is managing procedural issues if your licence requires you to include a copyright block at the top of source.

This was also briefly covered in the conditional compilation article. To recap

  • Most licences that recommend copyright headers require them to be at the top of the file, this means they must come before a package declaration, and its comment.
  • You probably don’t want the copyright header being part of your godoc, so the comment block holding the copyright header and the package declaration should be separated by a newline.
  • If you have any build tags, they should also appear between the copyright block and the package declaration. As all three are separate comment, they should be separated by a newline.
    // Copyright Commodore Inc, 1982
    
    // +build 6502
    
    // Package c64 is the computer for the masses, not the classes.
    package c64
  • If this leads to a verbose combination of copyright header, build tag, and package comment for godoc, consider moving the comment on the package declaration to a separate file. This is traditionally named doc.go and contains only the package declaration and its commentary.

Associative commentary

This is a quick post to discuss the rules of comments in Go.

To quickly recap, Go comments come in two forms

// everything from the double slash to the end of line is a comment
/* everything from the opening slash star, to the closing one is a comment */

As the first form declares that the remainder of the line is a comment, if you want to comment out more than one line, you need to do this

// this comment form is useful for
// commenting out sections of your code
// as you are working

The second form is also useful, and generally preferred, for large blocks of commentary

/*
The generally accepted rule when writing large
comment blocks in this form is to leave a newline
at the start and the end of your comment
*/

One important thing to note is that comments do not nest, thus

// // This is fine because everything from the double 
// // slash to the end of line is ignored

/* 
But, if you you were to start a new
/* comment inside an old one 
the closing star slash would close the comment block and */
this line would generate a syntax error 
*/

Association

A feature of the tools that consume Go source code, not the language, is the convention that a comment which directly preceeds a declaration is associated with that declaration.

// A Foo is a Fooid in the class of Endofoos.
func Foo() { .... }

Conversely, a comment followed by a newline stands alone, it’s just a comment.

package foo

// utility foos

func Quxx() { ... }

godoc allows comments to be associated with any of the top level declarations; package, var, const, type, and func.

import “C”

The trap that catches people out when they are using cgo is they don’t realise the significance of the newline, or more correctly, the lack of newline between their block of C code and the import "C" declaration.

package main

/*
#include "stdio.h"
*/
import "C"

func main() {
        C.printf(C.CString("Hello world\n"))
}

In this example the import "C" declaration is immediately preceded by the comment block containing our C code, in this case including stdio.h to obtain a reference to the printf function.

If there was a newline between the comment block and import "C" then the cgo preprocessor would not associate the comment with the import declaration and act as if #include "stdio.h" was never there.

% go run cgo.go
# command-line-arguments
37: error: use of undeclared identifier 'printf'

Update don’t forget to read the follow up to this post.