The Avid Gopher

Checking for empty structs

In some cases it is helpful to know wether the struct you are working with is empty or not. But sometimes things are not as simple as one might think.

A first naive try

Sometimes we need to check for an empty struct:

1
2
3
4
type Empty struct {
    Foo string
    Bar int
}

Our initial naive idea may look like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
package main

import "fmt"

func main() {
    mayBeEmpty := Empty{}

    if Empty{} == mayBeEmpty {
        fmt.Printf("it's empty")
    }
}

But Go’s compiler somehow rejects our efforts of compiling those grandiosity:

1
2
    syntax error: unexpected == at end of statement
    syntax error: non-declaration statement outside function body

The Problem

The problem is a parsing ambiguity which confuses the compiler as it does not understand the meaning of Empty{} == mayBeEmpty and expects a code-block right after the first curly brace.

Let me cite right from the docs to clear things up:

A parsing ambiguity arises when a composite literal using the TypeName form of the LiteralType appears as an operand between the keyword and the opening brace of the block of an “if”, “for”, or “switch” statement, and the composite literal is not enclosed in parentheses, square brackets, or curly braces. In this rare case, the opening brace of the literal is erroneously parsed as the one introducing the block of statements. To resolve the ambiguity, the composite literal must appear within parentheses.

Have a look at Composite Literals in the Go reference docs for further details.

The Solution

As supportive Gophers we will help the compiler evaluating the comparison by putting some braces around the Composite Literal:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
package main

import "fmt"

func main() {
    mayBeEmpty := Empty{}

    if (Empty{}) == mayBeEmpty {
        fmt.Printf("it's empty")
    }
}

But note that you can only compare zero valued composite literals, because only for them all fields are comparable. Something like this will not work:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
package main

import "fmt"

type NotComparable {
  Foo string
  Bar []int
}

func main() {
    notComparable := NotComparable{}

    if (NotComparable{}) == notComparable {
        fmt.Printf("it's empty")
    }
}

What about pointer comparison?

To compare pointer you have to dereference them first. If mayBeEmpty is a non-nil *Empty, then use:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
package main

import "fmt"

func main() {
    mayBeEmpty := &Empty{}

    if (Empty{}) == *mayBeEmpty {
        fmt.Printf("it's empty")
    }
}