typealias MustBeInTransaction = MyTransaction.() -> Unit
fun makeObject(i: Int): MustBeInTransaction {
return { /* do something with i or whatever in a transaction */ }
}
fun test() {
var genericArray = arrayOf(1, 2, 3).map { makeObject(it) }
//genericArray.forEach { it() } // fails to compile
transaction {
genericArray.forEach { it() }
}
}
Like that? type MustBeInTransaction = implicit MyTransaction => Unit
def makeObject(i: Int): MustBeInTransaction = {
return { /* do something with i or whatever in a transaction */ }
}
def test(): Unit = {
var genericArray = Array(1, 2, 3).map(makeObject)
//genericArray.forEach { _() } // fails to compile
transaction {
genericArray.forEach { _() }
}
}
EDIT - I just noticed that this is almost exactly the same as the example used in the function types link below[1] https://stackoverflow.com/questions/45875491/what-is-a-recei...
[2] https://kotlinlang.org/docs/reference/extensions.html
[3] https://www.scala-lang.org/blog/2016/12/07/implicit-function...
I think this issue with this is what happens when you combine DB transactions with async queries with errors and null handling? It seems like you have to combine 4 different mechanisms in order to do this (receivers, async/await, try/catch, if(null)). Is there some way to do this all with receivers? It seems like they don't really compose.
The 'command' version in Scala could be written roughly the same way for any combination of the 4 features (the types would just change). For example you could write your original example as:
def test() {
// update() compiles but doesn't do anything to the DB
val helloDBOperation = for {
result1 <- query()
_ <- update()
result2 <- query2()
} yield "Hello"
println("$hello") // prints "Hello"
}I think this issue with this is what happens when you combine DB transactions with async queries with errors and null handling? It seems like you have to combine 4 different mechanisms in order to do this (receivers, async/await, try/catch, if(null)). Is there some way to do this all with receivers? It seems like they don't really compose.
The 'command' version in Scala could be written roughly the same way for any combination of the 4 features (the types would just change). For example you could write a Scala version of your original example as:
def test(): Unit = {
// update() compiles but doesn't do anything to the DB
val helloDBOperation = for {
_ <- query()
_ <- update()
_ <- query2()
} yield "Hello"
val hello = db.run(helloDBOperation)
println("$hello") // prints "Hello"
}
This would look almost exactly the same no matter which combination of the 4 features you use.EDIT - it looks like I somehow also accidentally replied to you with an earlier version of this comment. Unfortunately , I didn't notice until it was too old to delete or edit. Please ignore the other comment that is very similar to this one. Sorry about the confusion.
https://kotlinlang.org/docs/reference/type-safe-builders.htm...
It's more designed to build DSLs or similar, so you'll find more documentaion/examples in that area of the docs.
> I think this issue with this is what happens when you combine DB transactions with async queries with errors and null handling? It seems like you have to combine 4 different mechanisms in order to do this (receivers, async/await, try/catch, if(null)). Is there some way to do this all with receivers? It seems like they don't really compose.
It's just a closure with a compiler-added paremeter. It can be nullable if you want and exceptions work the same as any other closure. If you want async/await you'd use coroutines. I think coroutines and receivers mix just fine, you'd just make the type a suspending lambda with receiver, but I've never tried.
Thanks for the link. However, I feel like that still doesn't give a lot of detail. Can you have multiple receivers? Can receivers be generic? Can receiver resolution be controlled by other arguments?
> It's just a closure with a compiler-added paremeter. It can be nullable if you want and exceptions work the same as any other closure. If you want async/await you'd use coroutines. I think coroutines and receivers mix just fine, you'd just make the type a suspending lambda with receiver, but I've never tried
Sorry I didn't mean to imply that Kotlin was incapable expressing all of these things together. I meant it would be desirable to express all of these things with the same tools. It seems like the you would have to express these with several different paradigms and be aware of how they interact. That also means you would need more boilerplate because you have to abstract each of these things separately.