Mike Hill
02/13/2020, 6:11 PMinline fun myInlineFun(myCase: Boolean, crossinline doSomething: () -> Unit) {
if (myCase) {
doSomething()
} else {
println("Start")
doSomething()
println("End")
}
}
The argument for the doSomething
param is written out twice in the resulting bytecode. Logically, this makes perfect sense to me -- unless there were a simple way for the compiler to remove the branches (which it does actually do if the condition is trivial, by the way), then the function must be written twice. It can have dangerous implications for uses though, especially if a caller attempts to use a long functional param.
I didn't notice a kotlinc or IntelliJ warning/inspection for this. Not sure if there are any other tools which would provide one.
Anybody else run into this?Zach Klippenstein (he/him) [MOD]
02/13/2020, 7:04 PMinline fun DB.withTransaction(block: Transaction.() -> Unit) {
startTransaction()
try {
block()
commitTransaction()
finally {
rollbackTransaction()
}
}
You can use noinline
on your function parameters to prevent them from being inlined.Mike Hill
02/13/2020, 7:30 PMblock()
call, particularly to guard against cases where block
is large, but this could easily be missed:
inline fun DB.withTransaction(block: Transaction.() -> Unit) {
if (!isTransactionAware) {
val t = startTransaction()
t.block()
t.commitTransaction()
return
}
val t = startTransaction()
try {
t.block()
t.commitTransaction()
} finally {
t.rollbackTransaction()
}
}
The object allocation avoidance would still yield a runtime benefit. However, the resulting class size for callers may become much greater than initially expected since the functional argument is now duplicated.
Take this usage example:
fun executeCriteria(db: DB) {
db.executeInTransaction {
// ... many criteria instructions ...
}
}
The compiled output would be equivalent to:
void executeCriteria(DB db) {
if (!db.isTransactionAware) {
Transaction t = db.startTransaction();
// ... many criteria instructions ...
t.commitTransaction();
return
}
Transaction t = db.startTransaction();
try {
// ... many criteria instructions ...
t.commitTransaction();
} finally {
t.rollbackTransaction();
}
}
I'm wondering if it would make sense to include a compiler warning in these cases.Kroppeb
02/13/2020, 8:10 PM