Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to keep track of the count of instances of a type?

In object oriented languages I use class variables to track how many instances are currently spawned by incrementing on construction and decrementing on destruction.

I try to implement similar behaviour in go:

package entity

type Entity struct {
    Name string
}

func New(name string) Entity {
    entity := Entity{name}
    counter++
    return entity
}

var counter int = 0

func (e *Entity) Count() int {
    return counter
}

and that works half way as I can not decrement the counter via a destructor.

Can I somehow mimic object destruction? How would I keep track of instance count correctly?

like image 694
matthias krull Avatar asked Nov 09 '12 13:11

matthias krull


People also ask

How do I count the number of instances of a class in Python?

You can use dir() function, which returns all properties and functions in the current script, to count the numbers of instances of a certain class.

How do you keep track of how many objects of a given class exist?

By putting the static variable with an increment operator in the constructor method, we can increment the value by 1 each time the constructor is called (when a new object is created). This allows us to keep track of the number of objects that have been created for a class.


2 Answers

You can use runtime.SetFinalizer like this. See here for playground version.

package main

import (
    "fmt"
    "runtime"
)

type Entity struct {
    Name string
}

var counter int = 0

func New(name string) Entity {
    entity := Entity{name}
    counter++
    runtime.SetFinalizer(&entity, func(_ *Entity) {
        counter--
    })
    return entity
}

func (e *Entity) Count() int {
    return counter
}

func main() {
    e := New("Sausage")
    fmt.Println("Entities", counter, e)
    e = New("Potato")
    fmt.Println("Entities", counter, e)
    runtime.GC()
    fmt.Println("Entities", counter)
    e = New("Leek")
    fmt.Println("Entities", counter)
    runtime.GC()
    fmt.Println("Entities", counter)
}

This prints

Entities 1 {Sausage}
Entities 2 {Potato}
Entities 0
Entities 1
Entities 0

Note this from the docs for gotchas with Finalizers

The finalizer for x is scheduled to run at some arbitrary time after x becomes unreachable. There is no guarantee that finalizers will run before a program exits, so typically they are useful only for releasing non-memory resources associated with an object during a long-running program.

like image 128
Nick Craig-Wood Avatar answered Oct 02 '22 16:10

Nick Craig-Wood


There was a discussion on golang-nuts about finalizers.

For now,

  • there is no finalizer function (edit : no reliable finalizer function, as was shown to me by Nick)
  • the GC doesn't use and doesn't maintain any reference count

So you have to manage your instance count yourself.

Usually, you don't have instances living on themselves, so for many practical uses (not including the profiling of a complex and hard to understand program), you can use defer to track the end of life of your variables. I won't pretend this really replaces finalizers but it's simple and often sufficient.

like image 35
Denys Séguret Avatar answered Oct 02 '22 15:10

Denys Séguret