61

I'm aware of two differences between Abstract classes and Interfaces in Kotlin:

  • An abstract class can have state (e.g. var...)
  • A class can implement multiple interfaces, but not multiple abstract classes.

Since Kotlin is a rather fresh language, I wonder why Abstract Classes were not abandoned? Interfaces seem superior tool, with a very little need for Abstract Classes.

To elaborate: Kotlin does support concrete function implementation in interfaces, e.g.:

interface Shiny {

    fun shine(amount : Int)  // abstract function

    fun reflect(s : String) { print ("**$s**") }  // concrete function

}

Can someone provide a strong practical example of the need for Abstract Classes?

Willi Mentzel
  • 27,862
  • 20
  • 113
  • 121
Lior Bar-On
  • 10,784
  • 5
  • 34
  • 46
  • 1
    this is practically the same thing as asking "why use abstract classes in java or c#" or any other object-oriented language – Salem Aug 10 '17 at 14:32
  • 5
    I don't think so: a. support of concrete function on interfaces - was not the state when this was answered. b. kotlin is fresh, and had a choice to abandon abstract classes (in compare to java - that must support backward compatibility) – Lior Bar-On Aug 10 '17 at 14:43
  • Kotlin does not implement anything with high overhead when compiling to the JVM. Being compatible with Java 6, it does not use Java 8-style interface default methods. – ephemient Aug 10 '17 at 14:58
  • @LiorBar-On I do - the answer to this question is practically identical to [Interface vs Abstract Class (general OO)](https://stackoverflow.com/questions/761194/interface-vs-abstract-class-general-oo). – Salem Aug 11 '17 at 04:57

3 Answers3

56

The practical side of abstract classes is that you can encapsulate a part of implementation that works with the state, so that it cannot be overridden in the derived classes.

In an interface, you can only define a property without a backing field, and an implementation class must override that property (with either a backing field or custom accessors).

Given that, you cannot define logic that stores some state in an interface in a reliable way: an implementation class might override the properties in an unexpected way.

Example:

interface MyContainer {
    var size: Int

    fun add(item: MyItem) { 
        // ...
        size = size + 1
    }
}

Here, we provide a default implementation for add that increments size. But it might break if an implementing class is defined like this:

class MyContainerImpl : MyContainer {
    override val size: Int 
        get() = 0
        set(value) { println("Just ignoring the $value") }
}

On contrary, abstract classes support this use case and thus allow you to provide some guarantees and contract for all their implementations: they can define some state and its transitions that will stay the same in a derived class.

Apart from that, abstract classes can have non-public API (internal, protected) and final members, whereas interfaces cannot (they can only have private members, which can be used in the default implementations), and all their default implementations can be overridden in the classes.

hotkey
  • 140,743
  • 39
  • 371
  • 326
  • 1
    "Apart from that, abstract classes can have non-public and final members, whereas interfaces cannot" - it seem interfaces can have `private` modifier for concrete function - you are right with the rest: all interface function are open and cannot be internal. – Lior Bar-On Aug 10 '17 at 15:53
  • 1
    @LiorBar-On, ah, indeed, these functions can be used in the default implementations and do not contribute to the API. Thanks, updated the asnwer. – hotkey Aug 10 '17 at 16:05
0

Abstract classes exist essentially for a hierarchy of classes. For example, if the abstract parent class had a concrete function that was also defined in the child class which extends the parent class, then in certain cases it would be necessary to call the parent's function. When you use an interface it is impossible to do so due to the entirely abstract nature of the class.

javajunkee
  • 35
  • 9
  • 1
    I'm not sure I understand: there is a support for concrete function implementation on Kotlin interfaces. I elaborated my question with an example. – Lior Bar-On Aug 10 '17 at 14:39
  • 1
    A quote from the Kotlin website "Interfaces in Kotlin are very similar to Java 8. They can contain declarations of abstract methods, as well as method implementations. What makes them different from abstract classes is that interfaces cannot store state. They can have properties but these need to be abstract or to provide accessor implementations." In addition to this, I believe it will also make a difference passing over an interface or an abstract class as an object, since a class will have the superclass of any, but I am not sure it is the case for an interface in Kotlin. – javajunkee Aug 10 '17 at 15:02
  • 3
    **This is not true**: in Kotlin, if an interface provides a default implementation, an implementing class can call that implementation with `super.f()`, see [**this runnable demo**](https://try.kotlinlang.org/#/UserProjects/5kt4plrlprfagq4me2ukjocph7/gc3nl1um36ouh7g592qnb0c6qb) – hotkey Aug 10 '17 at 15:33
  • @hotkey That's interesting. Why did the Kotlin team decide to develop the language that way (the way you explained in your answer) and not keep it standardized to java? – javajunkee Aug 10 '17 at 15:48
  • JetBrains publicly announced Kotlin in 2011. At that time, JSR-355 (lambda expressions and virtual extension methods in Java) was just an early draft. – ephemient Aug 10 '17 at 21:44
0

I am writing this answer to check my understanding as well.

  • Abstract classes can have constructors, init block and fields/properties so they can hold state
  • Interfaces cannot have the above.

With an Abstract class you can share state, on the other hand with an Interface you can share behaviour.

e.g

Imaging you have a shape class that has a default colour, common for all shapes, but each shape can have different implementation of the 'area', 'perimeter' or whichever other method might be needed, then the best tool to use for the job is the Abstract class.

vasilisdmr
  • 554
  • 8
  • 15
  • since kotlin 1.5 interfaces can declare property accessors with backing fields. something like `val text: String get() = "test"` – jane Aug 23 '23 at 12:09