You need a Money type and a Coordinates(lat, lng) type. For each, decide between a value class and a data class and justify the choice.
answer
- One scalar -> value class
- Two-plus fields -> data class
- Coordinates(lat,lng) can't be value class
- Money(cents) is a classic value class
- data class always allocates; value class often doesn't
basics
~10 sMoney is one value, so a value class fits and stays cheap. Coordinates has two fields, which a value class can't hold, so use a data class.
solid answer
~40 sMoney represents a **single scalar** (an amount, possibly with currency folded into the representation) — a perfect value class: one `val`, distinct type, validation in `init`, near-zero overhead via inlining. If Money truly needs both an amount and a currency as separate fields, that's two properties, so a value class is impossible and you'd use a `data class` (or fold currency in via a typed scalar like minor-units of a fixed currency). Coordinates(lat, lng) has **two** properties, so it cannot be a value class — use a `data class`, which gives `equals`/`hashCode`/`toString`/`copy` for the aggregate. Rule of thumb: **one meaningful scalar -> value class; an aggregate of two-plus fields -> data class.** Value classes win on overhead only when single-property; data classes always allocate but model structure.
go deeper
Picks data class for Coordinates because it has two fields; may not fully justify Money.
Correctly assigns value class to Money and data class to Coordinates and cites the one-property rule.
Justifies via allocation/inlining trade-offs and discusses how to handle amount+currency without two value-class fields.
Reasons about domain modeling, serialization, and performance at scale when choosing between typed scalars and aggregates across the codebase.
## The decision rule - **value class** = exactly **one** stored property. Use it to give a single scalar a distinct, safe type with (usually) no allocation overhead. - **data class** = an aggregate of **one or more** properties. It always allocates a real object but generates `equals()`, `hashCode()`, `toString()`, `copy()`, and `componentN()` for destructuring. ## Money If money is modeled as a single underlying value — e.g. an amount in minor units (cents) of an implied currency — it is one scalar and a great value class: ```kotlin @JvmInline value class Money(val cents: Long) { init { require(cents >= 0) { "negative money" } } val major: Double get() = cents / 100.0 operator fun plus(o: Money) = Money(cents + o.cents) } ``` This gives type safety (`Money` can't be passed where a raw `Long` count is expected), validation, and operator support — with the wrapper inlined away in the common case. If, instead, Money must carry **amount + currency** as two distinct fields, that's two properties and a value class is impossible — fall back to a `data class`: ```kotlin data class Money(val amount: BigDecimal, val currency: Currency) ``` ## Coordinates `Coordinates` inherently has **two** fields, latitude and longitude: ```kotlin data class Coordinates(val lat: Double, val lng: Double) ``` A value class **cannot** hold two properties, so it's out. A `data class` is correct: it gives structural `equals`/`hashCode` (so two equal coordinates compare equal), `copy(lat = ...)`, and destructuring `val (lat, lng) = c`. ## Why not always data class? A `data class` wrapping a single field still allocates an object on every instance and adds indirection. For a hot, ubiquitous single-value type (ids, money, measurements), a value class removes that cost while keeping the type safety. So pick value class precisely when the concept is a single scalar. ## Summary table - One scalar, want type safety + low overhead -> **value class** - Two-plus fields, want structural equality/copy -> **data class** - One field but you need full data-class API/heap identity for some reason -> data class ## Keywords single scalar vs aggregate, `init` validation, `copy()`, structural equality, inlining, allocation.
- If Money needs both amount and currency, can a value class still work?Not with two separate fields. You either fold currency into the representation (e.g. fixed-currency minor units, or encode it in the single value) or switch to a data class. Two distinct properties rule out a value class.
- Does a single-field data class give the same overhead win as a value class?No. A data class always allocates a heap object per instance. A value class is inlined to its underlying value in the common case, avoiding that allocation.
saying these in an interview costs you the question
- Trying to make Coordinates a value class with two fields
- Claiming data class and value class have identical overhead
- Saying value class gives copy()/componentN like data class
- Forcing every wrapper to be a value class regardless of fields
- Ignoring that value class is single-property only