3

In Kotlin I have this function to wrap a transaction:

fun wrapInTransaction(code: () -> Unit) {
        realmInstance.beginTransaction();
        code.invoke()
        realmInstance.commitTransaction();
}

How can I get access to realmInstance in the invoked code?

Lii
  • 11,553
  • 8
  • 64
  • 88
johnny_crq
  • 4,291
  • 5
  • 39
  • 64
  • Almost the same code is present in this question: http://stackoverflow.com/questions/34797366/in-kotlin-how-do-i-add-extension-methods-to-another-class-but-only-visible-in and explained in the accepted answer http://stackoverflow.com/a/34797367/3679676 where the transaction itself wraps the code. – Jayson Minard Jan 18 '16 at 12:22

3 Answers3

3

The easy solution here is to make code a function with receiver:

fun wrapInTransaction(code: Realm.() -> Unit) {
    realmInstance.beginTransaction();
    realmInstance.code()
    realmInstance.commitTransaction();
}

Inside a lambda which you pass as code you will be able to use this to reference the RealmInstance and to use its members directly as if inside a member function.

Calling realmInstance.code() is just calling code with passing realmInstance as a receiver to it.

Kirill Rakhman
  • 42,195
  • 18
  • 124
  • 148
hotkey
  • 140,743
  • 39
  • 371
  • 326
2

The other answers correctly demonstrate how to pass the RealmInstance object to the lambda. In addition, you can make the whole function an extension function which makes the call site a bit prettier:

fun Realm.wrapInTransaction(code: Realm.() -> Unit) {
    //this is implicit
    beginTransaction();
    code()
    commitTransaction();
}

The call site will look like this:

Realm.getInstance(this).wrapInTransaction {
    createObject(User.class)
}
Kirill Rakhman
  • 42,195
  • 18
  • 124
  • 148
1

Change the wrapInTransaction function to accept an extensions method on realmInstance like so:

fun wrapInTransaction(code:Realm.() -> Unit){
    realmInstance.beginTransaction();
    realmInstance.code()
    realmInstance.commitTransaction();
}

Then you can use it like:

wrapInTransaction {
    println("realm instance is $this, instanceId: $instanceId")
}

Where for the sake of the example the Realm looks like:

class Realm {
    val instanceId = 42
    fun beginTransaction() {
    }

    fun commitTransaction() {
    }
}

The above technique is possible thanks to Kotlin's Function Literals with Receiver that make it possible to set the this instance (receiver) within lambda function body. It makes it easy to build type safe builders that reassemble ones from Groovy or Ruby.

This answer provides more samples on the technique.

Community
  • 1
  • 1
miensol
  • 39,733
  • 7
  • 116
  • 112