Data, Sealed & Value Classes Interview Questions

KOTLIN › Types & Classes

Tell me about a time you used a data class where you probably shouldn't have. What went wrong, and what would you use instead?

What a strong answer covers: A strong answer usually lands on one of two classic misuses: putting a data class with a mutable var property into a HashSet or as a HashMap key, so equals/hashCode change after insertion and lookups silently fail, or using a data class purely as a mutable model that's mutated in place, where the auto-generated equals/copy/toString add no value and just obscure that it's really behaving like a plain class. The fix is usually making the fields val and immutable, or dropping data and writing explicit equality only where it's actually needed.

Why would you introduce a value class for something like UserId, and what's the practical maintenance cost, e.g. extra code, Java interop, or serialization?

What a strong answer covers: A strong answer explains the benefit is compile-time type safety, catching a bug like passing a TripId where a UserId is expected, at effectively zero runtime cost since the wrapper is erased to the underlying value at most call sites. The costs to flag: it only stays unboxed in direct usage since generics, collections, and nullable positions force boxing anyway, Java code sees a mangled or boxed representation and loses the ergonomics, and serialization libraries like Gson or Firestore's mapper often need custom handling since they don't natively understand the wrapper.

You have a sealed class hierarchy for UI state that's grown to 12 subclasses handled in one big when. What's your read on this design, and how would you refactor it?

What a strong answer covers: A strong answer recognizes that a sprawling flat sealed hierarchy handled in a single when is often a sign that orthogonal concerns, like loading/error/content plus several content variants, got merged into one type, making every consumer's when huge and every new case a ripple across the codebase. They'd suggest splitting into nested sealed hierarchies, an outer Loading/Error/Content split with Content itself sealed into its variants, so each when stays small and exhaustive at its own level, or extracting variants into plain data held by a single state where distinct branching isn't actually needed.

Back to Data, Sealed & Value Classes