Can a value class participate in inheritance — extend another class, be extended, or implement an interface? Why or why not?
answer
- No superclass, implicitly final
- Cannot be open / cannot be subclassed
- Interfaces ARE allowed
- No vtable/identity when inlined
- Polymorphism via interface, not base class
basics
~10 sA 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 sValue 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
Knows a value class can't be extended and has no superclass.
Explains it is implicitly final, can implement interfaces, and ties the no-inheritance rule to the inlined representation.
Knows interface usage can box and recommends interfaces over base classes for shared behavior across typed primitives.
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