skip to content

Can a value class participate in inheritance — extend another class, be extended, or implement an interface? Why or why not?

level: middleimportance: should knowfreq 45%

answer

  1. No superclass, implicitly final
  2. Cannot be open / cannot be subclassed
  3. Interfaces ARE allowed
  4. No vtable/identity when inlined
  5. Polymorphism via interface, not base class

basics

~10 s

A value class can't extend another class and can't be a parent of others — it's effectively final with no superclass. It can still implement interfaces.

solid answer

~30 s

Value classes don't support class inheritance: they cannot extend another class, and they are implicitly **final** so nothing can subclass them. The reason is the runtime representation — an inlined value class is just its underlying primitive, so there's no object identity or vtable to hang a class hierarchy on. They **can** implement **interfaces**, because interface dispatch doesn't require a superclass — though calling an interface method can cause **boxing** (a separate topic). This means value classes model leaf concepts, not hierarchies. If you need polymorphism over related id types, you express it via a shared interface, not a base class.

go deeper

for a junior

Knows a value class can't be extended and has no superclass.

for a middle

Explains it is implicitly final, can implement interfaces, and ties the no-inheritance rule to the inlined representation.

for a senior

Knows interface usage can box and recommends interfaces over base classes for shared behavior across typed primitives.

for a principal

Weighs the boxing cost of interface-based polymorphism in hot paths and designs id-type hierarchies accordingly.

## No class inheritance A **value class** sits outside the normal class-inheritance machinery: - It **cannot extend** another class (no `: SomeBaseClass()` superclass). - It is implicitly **final** — you cannot mark it `open`, so **nothing can subclass it**. ```kotlin // @JvmInline value class A(val v: Int) : SomeClass() // ERROR: no superclass allowed // open value class B(val v: Int) // ERROR: cannot be open ``` ### Why Class inheritance relies on each instance being a real heap object with a header and a **vtable** (the table used for virtual/overridable method dispatch) and a stable **identity**. An **inlined** value class has none of that in the common case — at runtime it is represented directly by its single underlying value (e.g. an `Int`). With no object header and no guaranteed identity, there's nothing for a subclass relationship to attach to. ## Interfaces are allowed Value classes **may implement interfaces**: ```kotlin interface Printable { fun printable(): String } @JvmInline value class Sku(val code: String) : Printable { override fun printable() = "SKU#$code" } ``` Interface dispatch doesn't require a superclass, so this is fine. Caveat: invoking the value class through its **interface type** (e.g. assigning a `Sku` to a `Printable` variable) generally forces **boxing** — wrapping it back into a real object — which is covered under boxing rules (a sibling topic). Functionally it works; just be aware of the cost. ## Modeling consequence Because there is no class hierarchy, value classes are **leaf** types: an id, an email, a measurement. To get polymorphism across several typed primitives (say all 'identifier' types), give them a **common interface** rather than a common base class. ## Keywords final, `open`, superclass, interface, vtable, polymorphism, leaf type.

  • If a value class implements an interface and you use it as that interface type, what happens at runtime?
    It gets boxed into a real wrapper object, since the interface reference needs an object with a vtable. The value is unboxed back when used directly as the value-class type. Boxing details are a separate topic.
  • How do you share behavior across several typed-id value classes?
    Define a common interface they all implement, or use extension functions. You cannot give them a shared base class.

saying these in an interview costs you the question

  • Claiming value classes can be `open` or subclassed
  • Saying a value class can extend a base class
  • Asserting interfaces are also forbidden
  • Not knowing interface use can trigger boxing
  • Suggesting an abstract base value class for shared logic

context