Comparing Kotlin's Companion Object vs Dart's Factory Keyword

Source: Nagaraj Alagusundaram

Introduction

In the world of programming languages, controlling object creation is a crucial aspect of software development. Kotlin and Dart, two popular languages, offer mechanisms to achieve this control. Kotlin provides the concept of a companion object, while Dart utilizes the factory keyword. In this blog post, we will explore and compare these features, discussing their purposes, usage patterns, and differences.

Companion Object in Kotlin

The companion object is a powerful feature in Kotlin, serving multiple purposes within a class. It is declared using the companion object keyword and provides a container for defining static members associated with the class. Let’s delve into its key aspects:

Purpose and Usage

The companion object is primarily used to define static members, such as properties and methods, specific to a class. It allows us to group these members together, providing a more organized and readable code structure. Furthermore, the companion object facilitates class-level access, enabling easy access to private members from outside the class.

class MyClass {
    companion object {
        val staticProperty = 10
        fun staticMethod() {
            // Perform some static operation
        }
    }
}

Singleton and Object Creation

While the companion object can be used to create instances of a class, its primary focus lies in providing a place for static members. The companion object is a singleton, meaning there is only one instance associated with the class. It cannot be instantiated directly and is accessed using the class name followed by the member name.

class SingletonClass {
    companion object {
        private val instance = SingletonClass()

        fun getInstance(): SingletonClass {
            return instance
        }
    }
}

Factory Keyword in Dart

Dart offers the factory keyword as a specialized constructor for controlling object creation. With the factory keyword, developers can customize the object creation process, allowing for flexible and dynamic instantiation. Let’s explore the key aspects of the factory keyword:

  1. Purpose and Usage: The factory keyword is used to define a factory constructor within a class. Unlike regular constructors, factory constructors are responsible for creating objects but also provide customization options. They enable developers to perform additional computations, apply logic, or even reuse existing instances during object creation.
class MyClass {
    final int value;

    MyClass(this.value);

    factory MyClass.fromAnotherObject(AnotherClass anotherObject) {
        // Perform some computations
        final modifiedValue = anotherObject.value * 2;
        return MyClass(modifiedValue);
    }
}
  1. Customization and Object Reuse: One significant advantage of the factory constructor is the ability to customize the object creation process. It allows for dynamic decision-making, enabling different object creation paths based on specific conditions or computations. Additionally, factory constructors can return existing instances of the class instead of always creating new ones. This opens up possibilities for object caching or object pooling techniques.
class SingletonClass {
    static SingletonClass _instance;

    SingletonClass._();

    factory SingletonClass.getInstance() {
        if (_instance == null) {
            _instance = SingletonClass._();
        }
        return _instance;
    }
}

Comparison and Conclusion

While both the companion object in Kotlin and the factory keyword in Dart offer mechanisms for controlling object creation, they serve different primary purposes and have distinct usage patterns.