Allocation

September 19, 2024

Today’s topic: Allocation!

What? You thought allocation was relegated to languages like C and C++?

Yeah, that’s actually pretty close to true. We’re not learning about malloc today. Rather, we’re learning about the built-in function new, which gives us just one (of many!) ways to allocate memory for a variable.

Allocation

The built-in function new takes a type T, allocates storage for a variable of that type at run time, and returns a value of type *T pointing to it. The variable is initialized as described in the section on initial values.

new(T)

For instance

type S struct { a int; b float64 }
new(S)

allocates storage for a variable of type S, initializes it (a=0, b=0.0), and returns a value of type *S containing the address of the location.

A natural, and expected, question after reading that, would be: Okay, but when would I use new, and why?

Before I answer that, let’s look at some equivalents and near equivalents.

type S struct { a int; b float64 }
x1 := &S{}
x2 := new(S)
var y *S
var z S
x3 := &z

In this code, x1, x2, and x3 are equivalent. They’re all pointers to an instance of the zero value of S. (They aren’t equal, in that they all point to distinct instances, so their pointer values are different.)

Of note, y, is not the same. It is of the same type, but it is actually a nil pointer of type *S.

So now then, let’s get back to when and why to use new as opposed to these alternatives.

First, var z S; x3 := &z is a rather cumbersome way to initialize x3, so it quickly falls out of the running. That leaves &S{} and new(S). Which to choose?

This mostly boils down to preference, in the majority of cases. My preferences is usually for the &S{} syntax. Most important, it’s easier to expand, if I later decide to initialize any of its members to a non-zero value:

x1 := &S{a: 3}

And that relates to the second point I’ll make, and when I might choose new as an alternative: If I want to convey semantically that the value I’m creating is explicitly a pointer to the zero value, I might choose new. It’s rare that I want to do this. It’s rare that I use new. Except…

The one exception to all this, is the one time when new is the only good option. When is that?

When you’re trying to create a new value within a generic function.

func Foo[T any]() (T, error) {
	/* Some logic */
	if err != nil {
		return nil, err
	}
	/* more logic */
}

This above code won’t work, because nil is not a valid value for all members of T. T might be a string or int, which cannot be nil. So how do we return the correct zero value of T?

Technically, there are options, but the most concise one is:

		return *new(T), err

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


Go 1.24.0 is here!

Go 1.24 is released! Yay! That means a short re-visit to the Go spec, as we look at things that have changed. From the release notes we see that there’s really only one significant change: Changes to the language¶ Go 1.24 now fully supports generic type aliases: a type alias may be parameterized like a defined type. See the language spec for details. For now, the feature can be disabled by setting GOEXPERIMENT=noaliastypeparams; but the aliastypeparams setting will be removed for Go 1.


unsafe.Slice

Package unsafe … The function Slice returns a slice whose underlying array starts at ptr and whose length and capacity are len. Slice(ptr, len) is equivalent to (*[len]ArbitraryType)(unsafe.Pointer(ptr))[:] except that, as a special case, if ptr is nil and len is zero, Slice returns nil [Go 1.17]. The len argument must be of integer type or an untyped constant. A constant len argument must be non-negative and representable by a value of type int; if it is an untyped constant it is given type int.


Zero values

I’m sorry for missing a couple days. We took an long weekend with some extended family to visit the beach here in Guatemala. But I’m back, and ready to talk about … zero values! Program initialization and execution The zero value When storage is allocated for a variable, either through a declaration or a call of new, or when a new value is created, either through a composite literal or a call of make, and no explicit initialization is provided, the variable or value is given a default value.

Get daily content like this in your inbox!

Subscribe