Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How kotlin delegation is useful?

Tags:

kotlin

I'm really confused about the kotlin delegation. Let me describe the regular polymorphism approach here which looks same like the kotlin delgation.

interface Base {
    fun print()
}
class BaseImpl(val x: Int) : Base {
    override fun print() { print(x) }
}
fun main(args: Array<String>) {
    val b : Base = BaseImpl(10)
    b.print() // prints 10
}

I can pass any implemented class of Base interface to b variable to call the method of specified class's object. Then what is the benefit of kotlin's delegation? Which is described here.

interface Base {
    fun print()
}
class BaseImpl(val x: Int) : Base {
    override fun print() { print(x) }
}
class Derived(b: Base) : Base by b // why extra line of code? 
                                   // if the above example works fine without it.
fun main(args: Array<String>) {
    val b = BaseImpl(10)
    Derived(b).print() // prints 10
}

I know this is the simple scenario where the both codes are working fine. There should be a benefit of delegation that's why kotlin introduced it. What is the difference? and how kotlin delegation can be useful? Please give me a working example to compare with polymorphism approach.

like image 889
Asif Mushtaq Avatar asked May 28 '17 20:05

Asif Mushtaq


People also ask

Why do we use delegation in Kotlin?

Android Dependency Injection using Dagger with Kotlin Kotlin supports “delegation” design pattern by introducing a new keyword “by”. Using this keyword or delegation methodology, Kotlin allows the derived class to access all the implemented public methods of an interface through a specific object.

What is the benefit of using interface delegation?

Interface delegation, in Kotlin, is a simple yet powerful technique that allows a class to delegate the actual implementation of the interfaces, to separate objects. NOTE: Kotlin interfaces support both abstract methods and abstract properties.

Why we use delegates in Android?

A delegate is just a class that provides the value for a property and handles its changes. This allows us to move, or delegate, the getter-setter logic from the property itself to a separate class, letting us reuse this logic.

Why is delegation pattern used?

In software engineering, the delegation pattern is an object-oriented design pattern that allows object composition to achieve the same code reuse as inheritance. In delegation, an object handles a request by delegating to a second object (the delegate). The delegate is a helper object, but with the original context.


2 Answers

Also remember that you're not restricted to just one delegate. Kotlin's way of implementing delegation is similar to traits implementation in languages like Groovy. You can compose different functionality via delegates. Kotlin's way can also be considered more powerful because you can "plug in" different implementations too.

interface Marks {
  fun printMarks()
}

class StdMarks() : Marks {
  override fun printMarks() { println("printed marks") }
}

class CsvMarks() : Marks {
  override fun printMarks() { println("printed csv marks") }
}

interface Totals {
  fun printTotals()
}

class StdTotals : Totals {
  override fun printTotals() { println("calculated and printed totals") }
}

class CheatTotals : Totals {
  override fun printTotals() { println("calculated and printed higher totals") }
}

class Student(val studentId: Int, marks: Marks, totals: Totals) 
  : Marks by marks, Totals by totals

fun main(args:Array<String>) {
  val student = Student(1,StdMarks(), StdTotals())
  student.printMarks()
  student.printTotals()
  val cheater = Student(1,CsvMarks(), CheatTotals())
  cheater.printMarks()
  cheater.printTotals()
}

Output:

printed marks
calculated and printed totals
printed csv marks
calculated and printed higher totals

You can't do this with inheritance.

like image 121
Strelok Avatar answered Oct 23 '22 13:10

Strelok


It is extremely useful for creating decorators and for object composition. Joshua Bloch in Effective Java, 2nd Edition, Item 16 'Favor Composition Over Inheritance' shows a good example: inheritance is easy-to-break, and decorators are not.

Inheritance:

class LoggingList<E> : ArrayList<E>() {

    override fun add(e: E): Boolean {
        println("added $e")
        return super.add(e)
    }

    override fun addAll(e: Collection<E>): Boolean {
        println("added all: $e")
        return super.addAll(e) // oops! Calls [add] internally.
    }

}

Delegation:

class LoggingList<E>(delegate: MutableList<E>) : MutableList<E> by delegate {

    override fun add(e: E): Boolean {
        println("added $e")
        return delegate.add(e)
    }

    override fun addAll(e: Collection<E>): Boolean {
        println("added all: $e")
        return delegate.addAll(e) // all OK
        // it calls [delegate]'s [add] internally, not ours
    }

}
like image 41
Miha_x64 Avatar answered Oct 23 '22 13:10

Miha_x64