Search code examples
kotlinoopextension-methodsgetter-setter

Kotlin - Extension Boolean property that returns true and then false (and so on)


I want an object to have a boolean property that returns true when I first get it, and the false, in a second time I get it. This must repeat every time I call it (if it is an even call, returns true; if it's an odd call, returns false).

I know I can achieve this in a class property like this:

class Foo {
    var bar: Boolean = true
        get() {
            val value = field
            bar = value.not()
            return value
        }
        private set
}

Test this snippet at: kotlinlang Playground


However, an extension property can't be implemented in the same way, like this:

var Foo.bar: Boolean = true // I get the first error here
    get() {
        val value = field // I get the second error here
        bar = value.not()
        return value
    }
    private set

Because I get two erros:

1: I can't initialize the variable

extension property cannot be initialized because it has no backing field


2: I can't have access to the field variable

Unresolved reference field


Is it possible to achieve what I want with kotlin?

BTW, I'm using the version 1.8.0 of the kotlin library on Android.


Solution

  • To achieve this, you need to store the state somewhere. You could do so in a global map, as shown by @broot. See their excellent answer for some more details on why a global map might not be a good idea.

    Implementation wise though, it might be nicer to hide the map in a property class:

    fun main() {
        val one = Foo()
        val two = Foo()
        println(one.bar) // false
        println(two.bar) // false
        println(one.bar) // true
        println(one.bar) // false
        println(two.bar) // true
        println(one.bar) // true
    }
    
    class Foo
    
    val Foo.bar by Alternate()
    
    class Alternate {
        private val values = mutableMapOf<Foo, Boolean>()
        
        operator fun getValue(foo: Foo, p: KProperty<*>): Boolean {
            val previous = values[foo] ?: true
            values[foo] = !previous
            return !previous
        }
    }
    

    Kotlin Playground