An empty heap is no use until it can hand out objects. Today you build allocation - New places an object in the lowest free slot and returns its id (a Ref) - so the heap starts filling up, one object at a time.
Allocate objects into successive free slots and return each object's id.
An object is just an entry in the heap table, and its id is the index of the slot
it lives in. We call that id a Ref - a reference to an object - because that is
exactly how objects will point at each other later: a field holding another object’s
id. To allocate, New takes the next slot marked by a cursor, puts a fresh object
there, advances the cursor, and returns that slot’s index as the Ref.
Give New the number of reference fields the object should have; create them all
holding the nil reference (Nil, the sentinel -1 that is never a real id). Two
allocations on a fresh 8-slot heap return ids 0 and 1 because the cursor starts at
0 and advances by one each time. That nil default matters: a brand-new object points at
nothing until you wire it up, which is the next two lessons. Reusing the slots a
collection frees comes later - for now the cursor only moves forward.
type Ref = intconst Nil Ref = -1 // the nil reference: a sentinel that is never a real object idtype object struct { fields []Ref }// returns (id, error); the error is always nil for now and earns its keep// once the heap can fill up, later in the projectfunc (h *Heap) New(nfields int) (Ref, error) {f := make([]Ref, nfields)for i := range f { f[i] = Nil } // every field starts pointing at nothingr := h.next // a cursor marking the next unused sloth.slots[r] = &object{fields: f}h.next++ // advance past the slot just handed outreturn r, nil}