skip to content

What are the requirements on a data class's primary constructor, and why won't `data class Empty()` compile?

level: juniorimportance: must knowfreq 70%

answer

  1. At least one primary-constructor param
  2. Every param must be val or var
  3. data class Empty() does not compile
  4. Bare param (no val/var) is a compile error
  5. Body properties are excluded from generated members

basics

~20 s

A data class must declare a primary constructor with at least one parameter, and every parameter must be marked val or var. An empty parameter list, or a plain parameter without val/var, is a compile error.

solid answer

~40 s

The Kotlin compiler enforces two rules on a data class primary constructor: (1) it must have at least one parameter, and (2) every primary-constructor parameter must be marked `val` or `var` so it becomes a property. `data class Empty()` fails because there are zero parameters, so the compiler cannot generate meaningful `equals`/`hashCode`/`toString`/`componentN`/`copy`. Likewise `data class P(x: Int)` fails because `x` is a constructor parameter, not a property — you must write `data class P(val x: Int)`. These rules exist because the generated members operate over the constructor properties; with no properties there is nothing to compare, hash, or destructure. Secondary constructors and an explicit body are still allowed, but they cannot satisfy the at-least-one-property requirement.

code

kotlin · 8 lines
kotlin
data class Empty()          // compile error: needs >= 1 param
data class Bad(x: Int)      // compile error: x must be val/var
data class Good(val x: Int) // OK

val a = Good(1)
val b = Good(1)
println(a == b)             // true (value equality)
println(a.copy(x = 2))      // Good(x=2)

go deeper

for a junior

Knows a data class needs at least one val/var parameter and can fix the compile error.

for a middle

Explains why the rules exist (generated members need properties) and that body properties are excluded.

for a senior

Connects the constraint to equals/hashCode/copy/componentN semantics and discusses the body-vs-constructor property distinction precisely.

for a principal

Frames the constraints as compiler-enforced invariants protecting value-semantics contracts, and reasons about API design implications when modeling value objects.

## What a data class is A `data class` is a class whose primary purpose is to hold data. The `data` keyword tells the Kotlin compiler to auto-generate `equals()`, `hashCode()`, `toString()`, `componentN()` functions (for destructuring), and `copy()` based on the properties declared in the **primary constructor**. ## The primary constructor The primary constructor is the parameter list written right after the class name: `class Point(val x: Int, val y: Int)`. A parameter prefixed with `val` (read-only) or `var` (mutable) is not just a constructor argument — it is automatically declared as a **property** (a field with a getter, and for `var` also a setter). ## Constraint 1 — at least one parameter The primary constructor must declare **at least one** parameter: ```kotlin data class Empty() // ERROR: Data class must have at least one primary constructor parameter data class User(val id: Int) // OK ``` Without properties, the generated members are meaningless (every instance would be equal, hash identically, and have nothing to destructure), so the compiler rejects it. ## Constraint 2 — every primary-constructor parameter must be val or var Each parameter in the primary constructor must be marked `val` or `var`: ```kotlin data class P(x: Int) // ERROR: Data class primary constructor parameters must be 'val' or 'var' data class P(val x: Int) // OK ``` A bare parameter (`x: Int`) is only visible inside `init` blocks and property initializers, not a property — so it cannot participate in the generated members. ## What is still allowed - A class **body** with extra members, methods, secondary constructors. - Properties declared **in the body** (not the constructor) — but these are **excluded** from `equals`/`hashCode`/`toString`/`copy`/`componentN`. ```kotlin data class User(val id: Int) { var lastSeen: Long = 0 // NOT part of equals/hashCode/copy } ``` ## Mnemonic summary - Need ≥1 primary-constructor parameter. - Each such parameter must be `val`/`var`. - Body properties are legal but ignored by generated members.

  • Can a data class have additional properties declared in its body?
    Yes, but they are excluded from the generated equals, hashCode, toString, copy, and componentN; only primary-constructor properties participate.
  • Does a data class with one val parameter still get all generated members?
    Yes — one property is enough; you get equals, hashCode, toString, component1, and copy.

A data class is like a labeled box: it needs at least one labeled compartment (a val/var property), or there is nothing to compare or copy.

saying these in an interview costs you the question

  • Claiming a data class can have zero parameters
  • Thinking a bare parameter (no val/var) is fine in a data class
  • Believing body-declared properties affect equals/hashCode
  • Saying the rule is about secondary constructors, not the primary one
  • Confusing 'parameter' with 'property' and assuming all params auto-become properties without val/var

context