Can an abstract class declare a member abstract when its superclass already provides a concrete (non-abstract) implementation of that member? When is this useful?
answer
- abstract override = re-abstract a concrete member
- drops inherited body for descendants
- super member must be open/abstract, not final
- re-abstracting class must be abstract
- breaking change to the extension contract
basics
~10 sYes. An abstract subclass can override an inherited open method and re-declare it as abstract, removing the inherited implementation and forcing its own subclasses to supply a new one.
solid answer
~40 sKotlin lets an abstract class override a concrete open member from its superclass and mark the override abstract — `abstract override fun f()`. This 'erases' the inherited implementation for the rest of the hierarchy below this class, forcing every concrete descendant to provide a fresh implementation. The superclass member must be open (or abstract) for the override to be legal, and the enclosing class must itself be abstract. This is useful when an intermediate type wants to invalidate a too-general default and demand a specialised one — for example a base Collection providing a default toString, but an abstract AbstractMatrix re-abstracting it so each matrix type must give an exact representation. It is the inverse of the common pattern where an abstract member gets a concrete override.
code
kotlin · 11 linesopen class Widget {
open fun id(): String = "widget" // open default
}
abstract class NamedWidget : Widget() {
abstract override fun id(): String // removes default; subclasses must override
}
class Button : NamedWidget() {
override fun id() = "button" // required now
}go deeper
Likely unaware this is possible; may think abstract-to-concrete is the only direction.
Knows the abstract override syntax exists and that the supermember must be open.
Explains the mechanism, the rules, and a concrete design reason (invalidating a too-general default) plus the breaking-change implication.
Evaluates re-abstraction as an API-evolution and contract-tightening tool and weighs it against composition or deprecation alternatives.
## The mechanism Normally inheritance moves from *abstract* (no body) toward *concrete* (body). Kotlin also allows the reverse step: an `abstract class` can take an inherited **concrete, open** member and re-declare it as `abstract`, dropping the inherited body. ```kotlin open class Base { open fun render(): String = "default" // concrete + open } abstract class Styled : Base() { abstract override fun render(): String // re-abstracted: no body again } class Card : Styled() { override fun render() = "card" // MUST implement; default is gone } ``` Without the `abstract override`, `Card` would inherit `"default"` and need no override. With it, `Styled` removes that default *for everything below it*, so `Card` is forced to provide its own. ## Rules - The inherited member must be `open` or `abstract` — you cannot override a `final` member, so you cannot re-abstract a final one. - The class doing the re-abstraction must itself be `abstract` (it now has an unimplemented member). - You still write `override` because you are overriding the inherited declaration; you add `abstract` to say the new declaration has no body. - Direct instantiation of `Styled` remains impossible. ## When it's useful - **Invalidating a too-permissive default.** A general base supplies a convenient default; an intermediate abstract type in a specific domain decides that default is wrong/unsafe and wants to *compel* a deliberate implementation in each leaf. - **Tightening a contract.** Frameworks use it so abstract base adapters force subclasses to override a method the platform class implemented loosely. ## Pitfalls It makes the hierarchy stricter: any existing concrete subclass that relied on the inherited default now fails to compile until it overrides. So treat re-abstraction as a breaking change to the extension contract.
- Could you re-abstract a `final` method from the superclass?No. A final member can't be overridden at all, so `abstract override` of it is a compile error. Only open or abstract members can be re-abstracted.
- Does re-abstracting affect classes that already extended the original concrete class?Only those extending through the re-abstracting class; any class that previously relied on the inherited default now must override it, making it a source-breaking change.
It's like a manager crossing out a default answer on a template and writing 'each team must fill this in themselves' — the convenient default no longer counts.
saying these in an interview costs you the question
- Claiming you cannot turn a concrete member back into an abstract one
- Trying to re-abstract a final member
- Forgetting the re-abstracting class must itself be abstract
- Omitting override and writing only abstract
- Not recognising it as a breaking change for existing subclasses