Difference between initialization and zeroing, and new() and make() in GoLang

new(T) allocates zeroed storage for a new item of type T and returns its address, a value of type *T: it returns a pointer to a newly allocated zero value of type T, ready for use; it applies to value types like arrays and structs. It is equivalent to &T{ }

make(T) returns an initialized value of type T; it applies only to the 3 built-in reference types: slices, maps, and channels.

var p *[]int = new([]int) // *p == nil; with len and cap 0
//or    
p := new([]int)

var v []int = make([]int, 10, 50)
//or
v := make([]int, 10, 50)

//This allocates an array of 50 ints and then creates a slice v with length 10 and capacity 50 pointing
//to the first 10 elements of the array

new returns a pointer to the type, and it's the only way to return a pointer to a native type in one step (aka int, float, complex):

intPtr := new(int)
// or
var i int
intPtr := &i

make is for initializing channels, slices and maps.

All variables are zeroed on creation, regardless of how you create them.

The spec about make: https://golang.org/ref/spec#Making_slices_maps_and_channels

The spec about zero value: https://golang.org/ref/spec#The_zero_value


I think I have figured it and decided to share what I figured so far.

make() vs. new()

I think I now understand the difference between make() and new(). At first, it was little confusing, but here what I got:

new is simply like new in C# or Java, but since there is no constructor in Go, all the fields (like in Java and C# terminology) will be zeroed. Zeroing means more like defaulting the fields. So if the field type is int, then it will be 0, or if it is a struct, then it will be defaulted to nil, and "" for string types. It is actually similar to C# and Java when there is only parameterless constructor available and you are not setting the members to something else manually.

However, types like map, slice, and channels are different. They are different because they are actually wrapper types that wrap an array type to hold the values behind the scenes. So something like List<T> or ArrayList in C# and Java. But using new is not enough in this situation, because the underlying array should be initialized to an empty array to be usable. Because you cannot add or remove from a field of type array which is nil (or null). Therefore, they provided a make() method to help you to initialize slices and such.

So what happens when you use new() over slices, for instance? Simple: Since the underlying array will be nil, the slice will be pointing at a nil array.

So new() would look like the following C#/Java code:

public class Person{
   public string Name;
   public int Age;
   public Address HomeAddress;
}

var person = new Person();
Console.WriteLine(person.Name); // ""
Console.WriteLine(person.Age); // 0
Console.WriteLine(person.HomeAddress); // null

make(), on the other hand, would look like this for slice,map, and channels:

public class PersonList{
   // We are initializing the array so that we can use it.
   // Its capacity can increase.
   private Person[] _personList = new Person[100];
   public void Add(Person p){}
   public void Remove(Person p){}
   public Person Get(int index){}
}

Initialization vs. Zeroing

Simply speaking, zeroing is a form of initialization. At first, I thought they were different but they are not. Initialization is a more general term, whereas if you are set the fields (properties, etc.) of a struct or a variable to its type default such as 0, nil, "", false, etc., then this is called zeroing. However, you can, for instance, use Composite Literals like hello := Hello{name="world"}, which is similar to var hello = new Hello() {Name = "World"} in C#, then you initialize your Hello object with a name field set to world.

In C#, at the time you say new List<string>(), [the underlying array field is initialized to a new array], and make) is performing a similar operation behind the scenes but as a language construct (built in the language itself):

(http://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs,cf7f4095e4de7646):

enter image description here

So new does zeroing and returns a pointer back. Whereas make() initializes to underlying array to an array with default values for each element and returns the value itself rather than a pointer.

Tags:

Go