ibelieve
07/09/2017, 9:19 PMolonho
07/10/2017, 11:41 AMtunedal
07/10/2017, 11:55 AMthis.myThing = wrappedLibrary.objectA.objectB.objectC.objectD.theThing
when accessing a foreign object system from Kotlin, e.g. GObject, COM, Python, ...?
You would want all the intermediate wrapped objects (objectA
, objectB
, ...) destroyed as soon as possible (perhaps scoped to the block) but theThing
to be left alive.olonho
07/10/2017, 1:42 PMclass ExternalObject(val id: Int) {
fun addRef() = println("addref on $id")
fun release() = println("release on $id")
}
interface ObjectOwner {
fun addObject(obj: ExternalObject)
fun addOwner(owner: ObjectOwner)
fun clear()
}
fun ObjectOwner.makeObject(id: Int): ExternalObject {
val result = ExternalObject(id)
this.addObject(result)
return result
}
open class Holder : ObjectOwner {
val objects = mutableListOf<ExternalObject>()
val owners = mutableListOf<ObjectOwner>()
constructor(parent: ObjectOwner? = null) {
if (parent != null) parent.addOwner(this)
}
override fun addObject(obj: ExternalObject): Unit {
// If we want more aggressive release strategy, we can use MutableSet for `objects`
// and release ASAP.
objects.add(obj)
obj.addRef()
}
override fun addOwner(owner: ObjectOwner): Unit {
owners.add(owner)
}
override fun clear() {
for (obj in objects) obj.release()
for (owner in owners) owner.clear()
}
}
class FieldOwner(parent: ObjectOwner) : Holder(parent) {
var objectField: ExternalObject? = null
set(value: ExternalObject?) {
field = value
if (value != null) addObject(value)
}
get() = field
}
inline fun <T> scoped(block: ObjectOwner.() -> T): T {
val scope = Holder()
try {
return scope.block()
} finally {
scope.clear()
}
}
fun main(args: Array<String>) {
scoped {
val owner = FieldOwner(this)
owner.objectField = makeObject(1)
scoped {
owner.objectField = makeObject(3)
}
owner.objectField = makeObject(2)
}
}
shows how one could think of such a cases