skip to content

When is the constructor keyword required in a Kotlin primary constructor, and what does a private primary constructor enable?

level: middleimportance: should knowfreq 55%

answer

  1. constructor keyword: only for modifiers or annotations
  2. private constructor → force factory creation
  3. Companion object can call private constructor
  4. private ctor ≠ singleton (use object)
  5. Visibility: public/internal/protected/private

basics

~10 s

Usually you skip the constructor keyword. You must write it when you add a visibility modifier like private, or an annotation. A private primary constructor stops outside code from calling it directly.

solid answer

~30 s

The `constructor` keyword in the class header is optional and almost always omitted. It is **required** when the primary constructor has a **visibility modifier** (`private`, `internal`, `protected`) or one or more **annotations** (e.g. `@Inject`, `@JvmOverloads`). A `private constructor` is a common idiom to force construction through factory functions or companion-object methods — useful for validation, caching, or enforcing invariants — and underpins the controlled-instantiation pattern. Note: making the primary constructor private does not by itself make the class a singleton; for singletons use `object`. Visibility on the constructor controls who may invoke it, independent of the class's own visibility.

code

kotlin · 10 lines
kotlin
class UserId private constructor(val raw: Long) {
    companion object {
        fun from(raw: Long): UserId {
            require(raw > 0) { "id must be positive" }
            return UserId(raw)
        }
    }
}
// UserId(5)        // error: constructor is private
UserId.from(5)       // ok, validated

go deeper

for a junior

Knows the constructor keyword is usually omitted.

for a middle

States the two cases requiring the keyword and the factory-via-private-constructor idiom.

for a senior

Explains companion-object access, smart constructors for invariants, and validation/normalization use cases.

for a principal

Designs construction policy for a library: factories vs constructors, ABI/visibility surface, and invariant enforcement strategy.

## The optional keyword Most classes never write `constructor`: ```kotlin class Point(val x: Int, val y: Int) ``` The keyword becomes **mandatory** in exactly two situations: ### 1. A visibility modifier on the constructor ```kotlin class Token private constructor(val value: String) class Cache internal constructor(val size: Int) ``` Visibility options: `public` (default), `internal` (same module), `protected` (open/abstract class subtypes), `private` (declaring class/file scope). ### 2. An annotation on the constructor ```kotlin class Service @Inject constructor(val repo: Repo) class Widget @JvmOverloads constructor(val w: Int = 0, val h: Int = 0) ``` ## Why use a private primary constructor A private constructor blocks direct `MyType(...)` calls from outside, channeling creation through **factory functions** — typically in the **companion object**: ```kotlin class Email private constructor(val value: String) { companion object { fun of(raw: String): Email { require("@" in raw) { "invalid email" } return Email(raw.trim().lowercase()) } } } ``` Benefits: - **Validation / normalization** before an instance exists. - **Caching / interning** (return a cached instance). - **Returning subtypes** from the factory. - Enforcing that all instances satisfy an invariant (a "smart constructor"). ## Misconceptions - Private constructor ≠ singleton. For a single instance use `object Foo`. - The companion object (declared inside the class) can still call the private constructor — private here means *within the class*, and the companion is a member. - Constructor visibility is separate from class visibility: a `public` class may have a `private` constructor. ## Interaction with sealed classes Many sealed-class hierarchies effectively have non-public constructors so subclasses are the only creators — though sealed restriction is its own mechanism.

  • Can the companion object call a private primary constructor?
    Yes. The companion object is a member of the class, so it has access to the private constructor — that is exactly how the factory pattern works.
  • Does a private primary constructor make the class a singleton?
    No. It only restricts who can construct it. Use an `object` declaration for a true singleton.

saying these in an interview costs you the question

  • Saying the constructor keyword is always required
  • Claiming a private constructor creates a singleton
  • Thinking the companion object can't access the private constructor
  • Confusing class visibility with constructor visibility
  • Forgetting annotations also force the constructor keyword

context