Constant lengths and expressions

September 13, 2024

A few of the built-in functions are very special, in that they can evaluate to constant expressions. len and cap are two such functions.

But they aren’t always evaluated to constant expressions, sometimes they’re more normal-ish runtime functions.

Length and capacity

The expression len(s) is constant if s is a string constant. The expressions len(s) and cap(s) are constants if the type of s is an array or pointer to an array and the expression s does not contain channel receives or (non-constant) function calls; in this case s is not evaluated. Otherwise, invocations of len and cap are not constant and s is evaluated.

const (
	c1 = imag(2i)                    // imag(2i) = 2.0 is a constant
	c2 = len([10]float64{2})         // [10]float64{2} contains no function calls
	c3 = len([10]float64{c1})        // [10]float64{c1} contains no function calls
	c4 = len([10]float64{imag(2i)})  // imag(2i) is a constant and no function call is issued
	c5 = len([10]float64{imag(z)})   // invalid: imag(z) is a (non-constant) function call
)
var z complex128

The example provided in the spec demonstrates a few examples of constant len() expressions by assigning the results to constants. But the fact that len() and cap() may resolve to constants has much more broad application.

First, it can be a simple compiler optimization to use constant expressions, rather than variable expressions, where possible. Take for example, something as simple as:

fmt.Println(len(x))

If the compiler is able to, according to the rules above, it will evaluate len(x) as a constant, and thus save the effort of calculating it every time the program runs this line of code. For something simple like a print statement, such an optimization is pretty accademic. But in some cases, such an optimization can be significant. And every little optimization adds up.

Quotes from The Go Programming Language Specification Language version go1.23 (June 13, 2024)


Share this

Direct to your inbox, daily. I respect your privacy .

Unsure? Browse the archive .

Related Content


Capacity of slices

Length and capacity … The capacity of a slice is the number of elements for which there is space allocated in the underlying array. At any time the following relationship holds: 0 <= len(s) <= cap(s) Recall that a slice is backed by a fixed-length array, which may have more elements than the slice. When this is the case, the capacity of the slice is said to be the current length of the slice, plus any unused elements in the backing array that extend beyond the final element of the slice.


Length and capacity

Length and capacity The built-in functions len and cap take arguments of various types and return a result of type int. The implementation guarantees that the result always fits into an int. Recall that int is either a 32- or 64-bit integer. So this means that the theoretical maximum length or capacity of the various types that support len and cap depends on the CPU architecture. However, this should not matter in practice, since you’d quickly exceed the available memory, before you had a slice, array, map, or other item with 2^32 elements in it.


Making slices, maps and channels

Making slices, maps and channels The built-in function make takes a type T, optionally followed by a type-specific list of expressions. The core type of T must be a slice, map or channel. It returns a value of type T (not *T). The memory is initialized as described in the section on initial values. Call Core type Result make(T, n) slice slice of type T with length n and capacity n make(T, n, m) slice slice of type T with length n and capacity m make(T) map map of type T make(T, n) map map of type T with initial space for approximately n elements make(T) channel unbuffered channel of type T make(T, n) channel buffered channel of type T, buffer size n The only time you absolutely need to use make is when creating channels.

Get daily content like this in your inbox!

Subscribe