Kotlin function parameter: Val cannot be reassigned

Anton Ostrouhhov picture Anton Ostrouhhov · Mar 1, 2017 · Viewed 35.9k times · Source

I have written Red–black tree in Kotlin. Fun insertFixup restores balance after inserting new element (z: Node? is new element). Algorithm of tree balancing is taken from here (pages 2-3). The problem is that Kotlin does not allow me to reassign z to z.parent and z.parent.parent. I want z to be a pointer. The question is how to make Kotlin understand what I want from him?

class Node(key: Int) {...}

class BinarySearchTree {
    var root: Node? = null

    fun insert(newNode: Node) {...}

    fun RotateLeft(x: Node?) {...}

    fun RotateRight(x: Node?) {...}

    fun insertFixup(z: Node?) {
        var y: Node?
        while (z?.parent?.color == "RED") {
            if (z?.parent == z?.parent?.parent?.left) {
                y = z?.parent?.parent?.right
                if (y?.color == "RED") {
                    z?.parent?.color = "BLACK"
                    y?.color = "BLACK"
                    z?.parent?.parent?.color = "RED"
                    z = z?.parent?.parent
                }
                if (z == z?.parent?.right) {
                    z = z?.parent
                    RotateLeft(z)
                    z?.parent?.color = "BLACK"
                    z?.parent?.parent?.color = "RED"
                    RotateRight(z?.parent?.parent)
                }
            } else {
                y = z?.parent?.parent?.left
                if (y?.color == "RED") {
                    z?.parent?.color = "BLACK"
                    y?.color = "BLACK"
                    z?.parent?.parent?.color = "RED"
                    z = z?.parent?.parent
                }
                if (z != z?.parent?.left) {
                    z = z?.parent
                    RotateLeft(z)
                    z?.parent?.color = "BLACK"
                    z?.parent?.parent?.color = "RED"
                    RotateRight(z?.parent?.parent)
                }
            }
        }
        root?.color = "BLACK"
    }
}

fun main(args: Array<String>) {
    val bst = BinarySearchTree()

    while (true) {
        var newNode = Node(readLine()!!.toInt())
        bst.insert(newNode)
        bst.insertFixup(newNode)
    }
}

UPD: Thanks to all! All the answers were helpful and I have found the solution in your replies.

Answer

zsmb13 picture zsmb13 · Mar 1, 2017

Function parameters in Kotlin are basically read-only val's inside the function, so z here will always refer to the original object that was passed in.

If you need to modify what it points to while your function is running, you'll have to make a local copy of it at the beginning of the function, and then you can make that a var.

For example, you could start your function like this, which lets you reassign this local var later:

fun insertFixup(_z: Node?) {
    var z = _z
    // ...
    z = z.parent
    // ...
}