Archive for 23 septiembre 2018

Covariance in Kotlin

septiembre 23, 2018

Implementation of https://www.linkedin.com/pulse/factory-method-pattern-kotlin-generics-v%C3%ADctor-mart%C3%ADn-molina/ using Covariance (now you can define functions like “someFunWithMagicRoom” thanks to “out T: Room”):

package org.myorg.generic

fun main(args: Array<String>) {
    val ordinaryGame = OrdinaryMazeGame()
    val magicGame = MagicMazeGame()
}

abstract class Room {
    fun connect(room: Room) {
    }
}

class MagicRoom : Room()

class OrdinaryRoom : Room()

class MagicMazeGame : MazeGame<MagicRoom>() {
    override fun makeRoom(): MagicRoom = MagicRoom()
}

class OrdinaryMazeGame : MazeGame<OrdinaryRoom>() {
    override fun makeRoom(): OrdinaryRoom = OrdinaryRoom()
}

fun someFunWithMagicRoom(m: MazeGame<MagicRoom>) {
    someFunWithRoom(m)
}

fun someFunWithRoom(m: MazeGame<Room>) {
}

abstract class MazeGame<out T: Room> {
    private val rooms = mutableListOf<T>()

    init {
        val room1 = makeRoom()
        val room2 = makeRoom()
        room1.connect(room2)
        rooms.add(room1)
        rooms.add(room2)
    }

    protected abstract fun makeRoom(): T
}

Anuncios

Factory method pattern in Kotlin (Generics)

septiembre 23, 2018

Implementation of https://www.linkedin.com/pulse/factory-method-pattern-kotlin-v%C3%ADctor-mart%C3%ADn-molina/ using Generics

fun main(args: Array<String>) {
    val ordinaryGame = OrdinaryMazeGame()
    val magicGame = MagicMazeGame()
}

abstract class Room {
    fun connect(room: Room) {
    }
}

class MagicRoom : Room()

class OrdinaryRoom : Room()

class MagicMazeGame : MazeGame<MagicRoom>() {
    override fun makeRoom(): MagicRoom = MagicRoom()
}

class OrdinaryMazeGame : MazeGame<OrdinaryRoom>() {
    override fun makeRoom(): OrdinaryRoom = OrdinaryRoom()
}

abstract class MazeGame<T: Room> {
    private val rooms = mutableListOf<T>()

    init {
        val room1 = makeRoom()
        val room2 = makeRoom()
        room1.connect(room2)
        rooms.add(room1)
        rooms.add(room2)
    }

    protected abstract fun makeRoom(): T
}

But these operations are dangerous because your class can be inherited, and a derived class is not yet initialized at this moment. Typical example:

package org.myorg

fun main(args: Array<String>) {
    testIt()
}

abstract class Base {
    val code = calculate()
    abstract fun calculate(): Int
}

class Derived(val x: Int) : Base() {
    override fun calculate(): Int {
        println("Derived.calculate: x is $x")

        return x
    }
}

fun testIt() {
    val d = Derived(42)
    println("testIt: d.code is ${d.code}") // Expected: 42, actual: 0
    println("testIt: d.x is ${d.x}")
}

Use-Site Variance: adding the following function to the main code:

fun <T: Room> someFun(r1: MutableList<T>, r2: MutableList<out T>) {
    r1[0].connect(r2[0])
}

you can now mix these subtypes:

fun mix() {
    val r1 = mutableListOf(MagicRoom()) as MutableList<Room>
    val r2 = mutableListOf(MagicRoom())

    someFun(r1, r2)
}

Factory method pattern in Kotlin

septiembre 22, 2018

Implementation of https://en.wikipedia.org/wiki/Factory_method_pattern#Java in Kotlin using companion object

package org.myorg

fun main(args: Array<String>) {
    val ordinaryGame = MazeGame.makeOrdinaryMazeGame()
    val magicGame = MazeGame.makeMagicMazeGame()
}

abstract class Room {
    fun connect(room: Room) {
    }
}

class MagicRoom : Room()

class OrdinaryRoom : Room()

class MazeGame private constructor(room1: Room, room2: Room) {
    private val rooms = mutableListOf<Room>()

    init {
        room1.connect(room2)
        rooms.add(room1)
        rooms.add(room2)
    }
    companion object {
        fun makeMagicMazeGame() = MazeGame(MagicRoom(), MagicRoom())
        fun makeOrdinaryMazeGame() = MazeGame(OrdinaryRoom(), OrdinaryRoom())
    }
}