How to Create Instances with Constructor References in Kotlin

Table of Contents

If you’ve been working with Kotlin for a while, you probably know how concise and expressive the language is. One of the features that makes Kotlin so enjoyable is its support for constructor references. This feature allows you to treat a constructor like a function and use it wherever a function is expected.

In this post, we’ll break down how to create instances with constructor references in Kotlin, step by step, using examples that are easy to follow. By the end, you’ll know exactly how and when to use this feature in real-world applications.

What are Constructor References in Kotlin?

In Kotlin, functions and constructors can be passed around just like any other value. A constructor reference is simply a shorthand way of pointing to a class’s constructor.

You use the :: operator before the class name to create a reference. For example:

Kotlin
class User(val name: String, val age: Int)

// Constructor reference
val userConstructor = ::User

Here, ::User is a reference to the User class constructor. Instead of calling User("amol", 25) directly, we can use the userConstructor variable as if it were a function.

Why Use Constructor References?

You might be wondering, why not just call the constructor directly?

Constructor references shine in situations where you need to pass a constructor as an argument. This is common when working with higher-order functions, factory patterns, or functional-style APIs like map.

It keeps your code clean, avoids repetition, and makes your intent very clear.

Creating Instances with Constructor References

Let’s walk through a few practical examples of how to create instances with constructor references in Kotlin.

Kotlin
class Person(val name: String, val age: Int)

fun main() {
    // Create a reference to the constructor
    val personConstructor = ::Person

    // Use the reference to create instances
    val person1 = personConstructor("amol", 30)
    val person2 = personConstructor("ashvini", 25)

    println(person1.name) // amol
    println(person2.age)  // 25
}
  • ::Person is a function reference to the constructor of Person.
  • You can then call it like any function: personConstructor("amol", 30).

Using with Higher-Order Functions

Suppose you have a list of names and ages, and you want to turn them into Person objects. Instead of writing a lambda, you can pass the constructor reference directly.

Kotlin
data class Person(val name: String, val age: Int)

fun main() {
    val peopleData = listOf(
        "amol" to 30,
        "ashvini" to 25,
        "swaraj" to 28
    )

    // Map each pair into a Person instance using constructor reference
    val people = peopleData.map { (name, age) -> Person(name, age) }

    println(people)
}

Now, let’s make it even cleaner using a constructor reference:

Kotlin
val people = peopleData.map { Person(it.first, it.second) }

While Kotlin doesn’t allow passing ::Person directly here (because the data is a Pair), constructor references can still simplify code in similar contexts.

With Function Types

Constructor references can also be stored in variables with a function type.

Kotlin
class Car(val brand: String)

fun main() {
    // Function type (String) -> Car
    val carFactory: (String) -> Car = ::Car

    val car = carFactory("Tesla")
    println(car.brand) // Tesla
}
  • ::Car matches the function type (String) -> Car.
  • Whenever you call carFactory("Tesla"), it creates a new Car instance.

Primary vs Secondary Constructors

Kotlin classes can have both primary and secondary constructors. Constructor references can point to either.

Kotlin
class Student(val name: String) {
    constructor(name: String, age: Int) : this(name) {
        println("Secondary constructor called with age $age")
    }
}

fun main() {
    val primaryRef: (String) -> Student = ::Student
    val secondaryRef: (String, Int) -> Student = ::Student

    val student1 = primaryRef("amol")
    val student2 = secondaryRef("ashvini", 20)
}

Here:

  • primaryRef points to the primary constructor.
  • secondaryRef points to the secondary constructor.

Real-World Use Case: Dependency Injection

In frameworks like Koin or Dagger, you often need to tell the system how to create objects. Constructor references make this simple:

Kotlin
class Repository(val db: Database)

class Database

fun main() {
    val dbFactory: () -> Database = ::Database
    val repoFactory: (Database) -> Repository = ::Repository

    val db = dbFactory()
    val repo = repoFactory(db)

    println(repo.db) // Instance of Database
}

This pattern is common when wiring dependencies because you can pass constructor references instead of custom lambdas.

Key Takeaways

  • Constructor references allow you to treat constructors like functions in Kotlin.
  • Use ::ClassName to get a reference.
  • They’re especially useful with higher-order functions, dependency injection, and factory patterns.
  • You can reference both primary and secondary constructors.
  • They make your code cleaner, shorter, and easier to maintain.

Conclusion

Knowing how to create instances with constructor references in Kotlin is a small but powerful tool in your Kotlin toolkit. It makes functional programming patterns more natural, simplifies object creation in higher-order functions, and improves readability.

If you want your Kotlin code to be more expressive and maintainable, start using constructor references where they fit. It’s a simple change with big payoffs.

Skill Up: Software & AI Updates!

Receive our latest insights and updates directly to your inbox

Related Posts

error: Content is protected !!