logo

Programming Languages - Constructors

Constructors

C++: YES

4 kinds:

  • Default Constructor: MyClass() {}
  • Parameterized Constructor: MyClass(int value) {}
  • Copy Constructor: MyClass(const MyClass& other) {}
  • Move Constructor: MyClass(MyClass&& other)

Java: YES

3 kinds: (no Move Constructor )

  • Default Constructor: MyClass() {}
  • Parameterized Constructor: MyClass(int value) {}
  • Copy Constructor: MyClass(MyClass other) {}

Kotlin: YES

A class in Kotlin has a primary constructor and possibly one or more secondary constructors.

The primary constructor is declared in the class header.

Go: NO

Go does not have constructors. Go uses factory functions, typically named NewT, to initialize and return instances of structs.

Why:

  • Simplicity: Go aims to minimize language features to keep the language easy to learn and use. Constructors, with their special syntax and rules, add complexity.
  • Explicitness: Go favors explicit initialization over implicit behavior. Factory functions make it clear how an object is being created and initialized.
  • Flexibility: Factory functions offer more flexibility than constructors. They can have different names, take varying arguments, and return different types (e.g., interfaces or errors). This allows for more complex initialization logic and error handling.
  • Zero Values: Go initializes variables with default zero values. For many types, this default initialization is sufficient, reducing the need for explicit constructors.

Rust: NO

From Rust doc:

There are no Copy, Default, Assignment, Move, or whatever constructors. The reasons for this are varied, but it largely boils down to Rust's philosophy of being explicit.

Python: YES

Use the __init__ method:

class Dog:
    def __init__(self, name, breed):
        self.name = name
        self.breed = breed

my_dog = Dog("Buddy", "Golden Retriever")

JavaScript: YES

class Dog {
  constructor(name, breed) {
    this.name = name;
    this.breed = breed;
  }
}

Destructors

C++: YES

Java: NO

finalize() is deprecated. Use try-with-resources.

Kotlin: NO

Use try-finally block similar to Java, or use use function to ensure that the close method is called (if the resource implements Closeable interface):

class MyResource : Closeable {
    fun doSomething() {
        println("Resource is being used")
    }

    override fun close() {
        println("Resource is being closed")
    }
}

fun main() {
    MyResource().use { resource ->
        resource.doSomething()
    }
}

Go: NO

Go does not have destructors as in C++.

Why:

  • Garbage Collection: Go is a garbage-collected language. The garbage collector (GC) is responsible for automatically reclaiming memory that is no longer reachable. This removes the need for manual memory deallocation, which is a common use case for destructors in languages like C++.
  • Non-Deterministic Cleanup: The timing of garbage collection in Go is non-deterministic. You cannot predict exactly when an object will be collected after it becomes unreachable. Relying on the GC to trigger resource cleanup (like closing files, network connections, or releasing locks) is unreliable and generally considered bad practice because resources could be held for an indeterminate amount of time, potentially leading to exhaustion.

Instead, use defer to handle resource cleanup:

func readFile(filename string) error {
  f, err := os.Open(filename)
  if err != nil {
    return fmt.Errorf("error opening file: %w", err)
  }
  // defer the Close call immediately after checking for the error
  defer f.Close() // This will run when readFile returns
  // ...
  return nil
}

defer: guarantees the method will run no matter if some code which executes after resource acquisition will panic() or not.

By convention, types that manage resources that need explicit cleanup (like *os.File, net.Conn, sql.DB) provide a Close() method. You use defer to call this method. The io.Closer interface standardizes this pattern.

Rust

Rust provides a full-blown automatic destructors through the Drop trait, which provides the following method:

fn drop(&mut self);

After drop is run, Rust will recursively try to drop all of the fields of self.

Python

Python has __del__() method that will be called when an object is garbage collected.