# Abstract Classes

An abstract class is like an ordinary class except one or more functions or properties is incomplete: a function lacks a definition or a property is declared without initialization. An interface is like an abstract class but without state.

You must use the abstract modifier to mark class members that have missing definitions. A class containing abstract functions or properties must also be marked abstract. Try removing any of the abstract modifiers below and see what message you get:

// Abstract/AbstractKeyword.kt
package abstractclasses

abstract class WithProperty {
  abstract val x: Int

abstract class WithFunctions {
  abstract fun f(): Int
  abstract fun g(n: Double)

WithProperty declares x with no initialization value (a declaration describes something without providing a definition to create storage for a value or code for a function). If there isn’t an initializer, Kotlin requires references to be abstract, and expects the abstract modifier on the class. Without an initializer, Kotlin cannot infer the type, so it also requires type information for an abstract reference.

WithFunctions declares f() and g() but provides no function definitions, again forcing you to add the abstract modifier to the functions and the containing class. If you don’t give a return type for the function, as with g(), Kotlin assumes it returns Unit.

Abstract functions and properties must somehow exist (be made concrete) in the class that you ultimately create from the abstract class.

All functions and properties declared in an interface are abstract by default, which makes an interface similar to an abstract class. When an interface contains a function or property declaration, the abstract modifier is redundant and can be removed. These two interfaces are equivalent:

// Abstract/Redundant.kt
package abstractclasses

interface Redundant {
  abstract val x: Int
  abstract fun f(): Int
  abstract fun g(n: Double)

interface Removed {
  val x: Int
  fun f(): Int
  fun g(n: Double)

The difference between interfaces and abstract classes is that an abstract class can contain state, while an interface cannot. State is the data stored inside properties. In the following, the state of IntList consists of the values stored in the properties name and list.

// Abstract/StateOfAClass.kt
package abstractstate
import atomictest.eq

class IntList(val name: String) {
  val list = mutableListOf<Int>()

fun main() {
  val ints = IntList("numbers")
  ints.name eq "numbers"
  ints.list += 7
  ints.list eq listOf(7)

An interface may declare properties, but actual data is only stored in classes that implement the interface. An interface isn’t allowed to store values in its properties:

// Abstract/NoStateInInterfaces.kt
package abstractclasses

interface IntList {
  val name: String
  // Doesn't compile:
  // val list = listOf(0)

Both interfaces and abstract classes can contain functions with implementations. You can call other abstract members from such functions:

// Abstract/Implementations.kt
package abstractclasses
import atomictest.eq

interface Parent {
  val ch: Char
  fun f(): Int
  fun g() = "ch = $ch; f() = ${f()}"

class Actual(
  override val ch: Char        // [1]
): Parent {
  override fun f() = 17        // [2]

class Other : Parent {
  override val ch: Char        // [3]
    get() = 'B'
  override fun f() = 34        // [4]

fun main() {
  Actual('A').g() eq "ch = A; f() = 17" // [5]
  Other().g() eq "ch = B; f() = 34"     // [6]

Parent declares an abstract property ch and an abstract function f() that must be overridden in any implementing classes. Lines [1]-[4] show different implementations of these members in subclasses.

Parent.g() uses abstract members that have no definitions at the point where g() is defined. Interfaces and abstract classes guarantee that all abstract properties and functions are implemented before any objects can be created—and you can’t call a member function unless you’ve got an object. Lines [5] and [6] call different implementations of ch and f().

Because an interface can contain function implementations, it can also contain custom property accessors if the corresponding property doesn’t change state:

// Abstract/PropertyAccessor.kt
package abstractclasses
import atomictest.eq

interface PropertyAccessor {
  val a: Int
    get() = 11

class Impl : PropertyAccessor

fun main() {
  Impl().a eq 11

You might wonder why we need interfaces when abstract classes are more powerful. To understand the importance of “a class without state,” let’s look at the concept of multiple inheritance, which Kotlin doesn’t support. In Kotlin, a class can only inherit from a single base class:

// Abstract/NoMultipleInheritance.kt
package multipleinheritance1

open class Animal
open class Mammal : Animal()
open class AquaticAnimal : Animal()

// More than one base class doesn't compile:
// class Dolphin : Mammal(), AquaticAnimal()

Trying to compile the commented code produces an error: Only one class may appear in a supertype list.

Java works the same way. The original Java designers decided that C++ multiple inheritance was a bad idea. The main complexity and dissatisfaction at that time came from multiple state inheritance. The rules managing inheritance of multiple states are complicated and can easily cause confusion and surprising behavior. Java added an elegant solution to this problem by introducing interfaces, which can’t contain state. Java forbids multiple state inheritance, but allows multiple interface inheritance, and Kotlin follows this design:

// Abstract/MultipleInterfaceInheritance.kt
package multipleinheritance2

interface Animal
interface Mammal: Animal
interface AquaticAnimal: Animal

class Dolphin : Mammal, AquaticAnimal

Note that, just like classes, interfaces can inherit from each other.

When inheriting from several interfaces, it’s possible to simultaneously override two or more functions with the same signature (the name combined with the parameters and return type). If function or property signatures collide, you must resolve the collisions by hand, as seen in class C:

// Abstract/InterfaceCollision.kt
package collision
import atomictest.eq

interface A {
  fun f() = 1
  fun g() = "A.g"
  val n: Double
    get() = 1.1

interface B {
  fun f() = 2
  fun g() = "B.g"
  val n: Double
    get() = 2.2

class C : A, B {
  override fun f() = 0
  override fun g() = super<A>.g()
  override val n: Double
    get() = super<A>.n + super<B>.n

fun main() {
  val c = C()
  c.f() eq 0
  c.g() eq "A.g"
  c.n eq 3.3

The functions f() and g() and the property n have identical signatures in interfaces A and B, so Kotlin doesn’t know what to do and produces an error message if you don’t resolve the issue (try individually commenting the definitions in C). Member functions and properties can be overridden with new definitions as in f(), but functions can also access the base versions of themselves using the super keyword, specifying the base class in angle brackets, as in the definition of C.g() and C.n.

Collisions where the identifier is the same but the type is different are not allowed in Kotlin and cannot be resolved.

Exercises and solutions can be found at www.AtomicKotlin.com.