Book Image

Functional Kotlin

Book Image

Functional Kotlin

Overview of this book

Functional programming makes your application faster, improves performance, and increases your productivity. Kotlin supports many of the popular and advanced functional features of functional languages. This book will cover the A-Z of functional programming in Kotlin. This book bridges the language gap for Kotlin developers by showing you how to create and consume functional constructs in Kotlin. We also bridge the domain gap by showing how functional constructs can be applied in business scenarios. We’ll take you through lambdas, pattern matching, immutability, and help you develop a deep understanding of the concepts and practices of functional programming. If you want learn to address problems using Recursion, Koltin has support for it as well. You’ll also learn how to use the funKtionale library to perform currying and lazy programming and more. Finally, you’ll learn functional design patterns and techniques that will make you a better programmer.By the end of the book, you will be more confident in your functional programming skills and will be able to apply them while programming in Kotlin.
Table of Contents (22 chapters)
Title Page
Copyright and Credits
Dedication
Packt Upsell
Contributors
Preface
Index

Interfaces


The open and abstract classes are great for creating hierarchies, but sometimes they aren't enough. Some subsets can span between apparently unrelated hierarchies, for example, birds and great apes are bipedal, and both are animals and vertebrates, but they not directly related. That is why we need a different construct and Kotlin gives us interfaces (other languages deal with this problem differently).

Our bakery goods are great, but we need to cook them first:

abstract class BakeryGood(val flavour: String) { 
  fun eat(): String { 
    return "nom, nom, nom... delicious $flavour ${name()}" 
  } 

  fun bake(): String { 
    return "is hot here, isn't??" 
  } 

  abstract fun name(): String 
}

With our new bake() method , it will cook all our amazing products, but wait, donuts aren't baked, but fried.

What if we could move the  bake() method to a second abstract class, Bakeable? Let's try it in the following code:

abstract class Bakeable { 
  fun bake(): String { 
    return "is hot here, isn't??" 
  } 
} 

class Cupcake(flavour: String) : BakeryGood(flavour), Bakeable() { //Compilation error: Only one class may appear in a supertype list 
  override fun name(): String { 
    return "cupcake" 
 }
}

Wrong! In Kotlin, a class can't extend two classes at the same time. Let's have a look at the following code:

interface Bakeable { 
  fun bake(): String { 
    return "is hot here, isn't??" 
  } 
} 

class Cupcake(flavour: String) : BakeryGood(flavour), Bakeable { 
  override fun name(): String { 
    return "cupcake" 
  } 
}

However, it can extend many interfaces. An interface is a type that defines a behavior; in the Bakeable interface's case, that is the bake() method.

So, what are the differences between an open/abstract class and an interface?

Let's start with the following similarities:

  • Both are types. In our example, Cupcake has an is-a relationship with BakeryGood and has an is-a relationship with Bakeable.
  • Both define behaviors as methods.
  • Although open classes can be instantiated directly, neither abstract classes nor interfaces can.

Now, let's look at the following differences:

  • A class can extend just one class (open or abstract), but can extend many interfaces.
  • An open/abstract class can have constructors.
  • An open/abstract class can initialize its own values. An interface's values must be initialized in the classes that extend the interface.
  • An open class must declare the methods that can be overridden as open. An abstract class could have both open and abstract methods.

In an interface, all methods are open and a method with no implementation doesn't need an abstract modifier:

interface Fried { 
  fun fry(): String 
} 

open class Donut(flavour: String, val topping: String) : BakeryGood(flavour), Fried { 
  override fun fry(): String { 
    return "*swimming on oil*" 
  } 

  override fun name(): String { 
    return "donut with $topping topping" 
  } 
}

When should you use one or the other?:

  • Use open class when:
    • The class should be extended and instantiated
  • Use abstract class when:
    • The class can't be instantiated
    • A constructor is needed it
    • There is initialization logic (using init blocks)

Let's have a look at the following code:

abstract class BakeryGood(val flavour: String) {
init {
    println("Preparing a new bakery good") 
  } 

  fun eat(): String { 
    return "nom, nom, nom... delicious $flavour ${name()}" 
  } 

  abstract fun name(): String 
}
  • Use interface when:
    • Multiple inheritances must be applied
    • No initialized logic is needed

Note

My recommendation is that you should always start with an interface. Interfaces are more straightforward and cleaner; they also allow a more modular design. In the case that data initialization/constructors are needed, move to abstract/open.

As with abstract classes, object expressions can be used with interfaces:

val somethingFried = object : Fried { 
  override fun fry(): String { 
    return "TEST_3" 
  } 
}