What are the structural constraints on a value class — how many properties can it have, and can it have ordinary properties with backing fields?
answer
- Exactly ONE val property
- No extra backing-field properties
- Computed getters + methods are OK
- Property must be val, not var
- init validation since 1.4.30
basics
~10 sA value class must have exactly one value (one constructor property). It can't have extra stored properties — only computed ones. That single value is what it really is underneath.
solid answer
~40 sA value class must wrap **exactly one** property, declared `val` in the primary constructor. You cannot add more constructor properties, and you cannot add ordinary class-body properties that have a **backing field** (stored state) — because at runtime the class is represented by that single underlying value, there's nowhere to store extra fields. You *can* add properties with custom getters (computed, no backing field) and you *can* add functions/methods. The single property does not have to be a primitive; it can be any type, though primitives/String give the most benefit. This single-property rule is why value classes model 'one scalar concept' — an id, an email, a money amount — rather than aggregates.
code
kotlin · 6 lines@JvmInline value class Email(val value: String) {
init { require("@" in value) { "invalid email" } }
val domain: String get() = value.substringAfter('@') // computed, OK
fun masked(): String = "***@" + domain // method, OK
// val parts = value.split('@') // ERROR: backing field not allowed
}go deeper
Knows there must be exactly one property and it is the underlying value.
Explains backing-field properties are disallowed but computed getters and methods are fine, and ties this to the inlined runtime representation.
Connects the constraint to immutability and the 'single scalar concept' modeling rule, and knows init validation is supported.
Reasons about when the single-property limit should push a design toward a data class or a sealed model, and about library/API stability of value-class members.
## The one-property rule A **value class** must declare **exactly one** property in its **primary constructor**, and that property must be `val` (read-only): ```kotlin @JvmInline value class Meters(val value: Double) // OK // @JvmInline value class Point(val x: Int, val y: Int) // ERROR: needs exactly one property ``` The reason is the runtime model: the compiler **inlines** the class so that, in the common case, an instance is represented directly by its single underlying value. There is no wrapper object to hold a second field, so a second stored property is impossible. ## Backing fields are not allowed (beyond the one) A **backing field** is the hidden storage that an ordinary property uses to hold its value. Because a value class has room for only the one underlying value, you **cannot** declare additional properties that need backing fields: ```kotlin @JvmInline value class Celsius(val value: Double) { // val cached: Double = value * 2 // ERROR: would need a backing field val fahrenheit: Double get() = value * 9 / 5 + 32 // OK: computed, no backing field } ``` Properties with a **custom getter** (computed each access, no stored state) are fine, as are member functions. ## What you still get - **Methods and computed properties** — so a value class can carry behavior (e.g. `Email.domain`). - **`init` block** for validation, supported since Kotlin **1.4.30** (the prompt's 'pre-1.x' phrasing predates the stable feature; in modern Kotlin 2.x `init` is available). - **Interface implementation** — a value class may implement interfaces (it just can't extend a class). ## What you don't get - More than one stored property. - A `var` constructor property (must be `val`, immutable). - Extra stored/backing-field properties. ## Mental model Think of a value class as a **typed alias for one value plus optional behavior**: it is its single property at runtime, dressed up with a distinct type and methods. ## Keywords primary constructor, single `val`, backing field, custom getter, `init` block, computed property.
- Can a value class hold a `var` instead of `val`?No. The single constructor property must be `val`. Value classes are immutable by design; their identity is the underlying value, so mutation isn't supported.
- If you need two fields, like x and y for a point, what should you use?A regular `data class`. Value classes model a single scalar concept; an aggregate of two-plus fields is exactly what a data class is for.
saying these in an interview costs you the question
- Saying a value class can have two properties if one is computed
- Claiming you can add stored properties in the body
- Allowing a var property in a value class
- Confusing computed getters (allowed) with backing-field props (not)
- Thinking value class replaces data class for multi-field types