Passing delegated properties to functions (instead of wrapping it in class with one property)


#1

I recently wrote something like RxJava but crossplatform for my project and I had to implement functionality of “isDisposed” that calls “isCancelled” in my lib.
I chose approach that differs from RxJava’s. I just pass Boolean that wrapped in object (somenting like AtomicBoolean) as last parameter.

abstract class Observable {
    fun subscribe() {
        val isCancelled = AtomicBoolean()
        doWork(isCancelled)
    }
    abstract fun doWork(isCancelled: AtomicBoolean)
}

class MyObservable : Observable() {
    override fun doWork(isCancelled: AtomicBoolean) {
        if (!isCancelled.get()) {
            // do work
        }
    }
}

If I want to prevent modifying “isCancelled” by user of my lib I go to write my own wrapper on Boolean.

class ReadOnlyBoolean(
        private val atomic: AtomicBoolean) {
    val value get() = atomic.get()
}

But I don’t want to write a class. I just want to give my user one read-only property. Of course I not suggesting to allow passing refs on variables how it implemented in C. In Kotlin it can be done much more safe through delegates.

In current syntax:

class AtomicBooleanDelegate {
    val source = AtomicBoolean()
    operator fun getValue(thisRef: Any?, property: KProperty<*>) = source.get()
    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Boolean) {
        source.set(value)
    }
}

abstract class Observable {
    fun subscribe() {
        val isCancelledDelegate = AtomicBooleanDelegate()
        doWork(isCancelledDelegate)
    }
    abstract fun doWork(isCancelledDelegate: AtomicBooleanDelegate)
}

class MyObservable : Observable() {
    override fun doWork(isCancelledDelegate: AtomicBooleanDelegate) {
        // user still can declare isCancelled as var
        // and modify it
        val isCancelled by isCancelledDelegate 
        if (!isCancelled) {
            // do work
        }
    }
}

In syntax that I suggest:

class AtomicBooleanDelegate {
    val source = AtomicBoolean()
    operator fun getValue(thisRef: Any?, property: KProperty<*>) = source.get()
    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Boolean) {
        source.set(value)
    }
}

abstract class Observable {
    fun subscribe() {
        var isCancelled by AtomicBooleanDelegate()
        doWork(delegate isCancelled)
    }
    abstract fun doWork(delegate val isCancelled: Boolean)
}

class MyObservable : Observable() {
    override fun doWork(delegate val isCancelled: Boolean) {
        if (!isCancelled) {
            // do work
        }
    }
}

Or just

abstract class Observable {
    var isCancelled = false
    fun subscribe() {
        // automatically create observable delegate there
        doWork(delegate isCancelled)
    }
    abstract fun doWork(delegate val isCancelled: Boolean)
}

class MyObservable : Observable() {
    override fun doWork(delegate val isCancelled: Boolean) {
        if (!isCancelled) {
            // do work
        }
    }
}

if we don’t need a atomicity.

I think this feature may be useful because wrapping property in object to add additional functionality and passing it in functions is common use case.
Indeed interoperability with java will not be broken. We can just create and pass delegate to this function.

P.S. Sorry for my English.