DEV Community

Saleh Rahimzadeh
Saleh Rahimzadeh

Posted on

Compile-Time Assertions in Go (Golang)

A compile-time assertion is a mechanism used to enforce certain conditions or constraints at compile time rather than at runtime. If the condition is not met, the compilation process fails, and an error is generated. This is particularly useful for catching errors early in the development process, ensuring that certain invariants or assumptions hold true before the program is even executed.

Compile-time assertions are often used to:

  • Ensure the size of a data structure is as expected.
  • Verify that certain constants or expressions evaluate to specific values.
  • Enforce type constraints or other compile-time checks.

Compile-Time Assertions in Go

Go does not have built-in support for compile-time assertions like some other languages. However, you can achieve similar functionality using creative techniques. Below are some common approaches.

Assert a constant boolean expression is true (or false) at compile time:

We could make use of the fact introduced in the following:

Go specification clearly specifies that the constant keys in a map/slice/array composite literal must not be duplicate.

For example, the following code assures that the constant boolean expression aBoolConst must be true.
If it is not true, then the code fails to compile.

const aBoolConst = true
var _ = map[bool]int{false: 0, aBoolConst: 1}
Enter fullscreen mode Exit fullscreen mode

Assert the length of a constant string is 15:

const STR = "abcdefghij12345"
var _ = map[bool]int{false: 0, len(STR) == 15: 1}
Enter fullscreen mode Exit fullscreen mode

Assert a constant integer is 15:

var _ = [1]int{len(STR)-15: 0}
//OR
var _ = [1]int{}[len(STR)-15]
Enter fullscreen mode Exit fullscreen mode

Assert a constant X is not smaller than another constant Y at compile time:

const _ uint = X-Y
//OR
type _ [X-Y]int
Enter fullscreen mode Exit fullscreen mode

Assert a constant string is not blank:

var _ = aStringConst[0]
//OR
const _ = 1/len(aStringConst)
Enter fullscreen mode Exit fullscreen mode

Using array size checks:

import "unsafe"

type MyStruct struct {
    A int64
    B int64
}

// Ensure the size of a struct is 16 bytes
var _ = [1]int{unsafe.Sizeof(MyStruct{}) - 16: 0}
Enter fullscreen mode Exit fullscreen mode

Assert enum length:

type enumType int

const (
    EnumA enumType = iota
    EnumB
    EnumC
    end
)

var enumDescriptions = [...]string {
    EnumA: "first",
    EnumB: "second",
    EnumC: "third",
}

func (e enumType) String() string {
    if e < 0 || e >= end {
        panic("invalid value")
    }
    return enumDescriptions[e]
}

var _ = [1]int{}[len(enumDescriptions) - int(end)]

func _() {
    var x [1]struct{}
    _ = x[EnumA - 0]
    _ = x[EnumB - 1]
    _ = x[EnumC - 2]
}
Enter fullscreen mode Exit fullscreen mode

Using init function with panic:

While not strictly a compile-time assertion, you can use the init function to perform checks that will fail at program startup (effectively acting as a runtime assertion during initialization):

const ExpectedSize = 8

var myInt int64

func init() {
    if unsafe.Sizeof(myInt) != ExpectedSize {
        panic("int size is not 8 bytes")
    }
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)