It turns out the compiler is not smart enough to deal with also here but if you used let it would work without the cast:
val img : Image = reader.acquireLatestImage() ?: Log.d(TAG, "Image is null!").let { return }
This is because the type of Log.d(...) is Unit, so the type of Log.d(...).also { ... } is also Unit in general. The compiler doesn't see that the non-local return in this specific case will prevent the whole expression Log.d(...).also { ... } from resulting in a value (in practice it should have the type Nothing, but the compiler doesn't see it and still gives it the type Unit).
let, on the contrary, returns the value of the lambda expression, which in this case is really of type Nothing and therefore is correctly understood by the compiler.
Another option would be to reverse your null-handling section:
val img = reader.acquireLatestImage() ?: return Unit.also { Log.d(TAG, "Image is null!!") }
Is it the best way to do it?
In this form, I'm not convinced even by my own versions, which are probably not the most maintainable way of doing it. I would personally favor a plain if statement here for the log and return. The smart casting of Kotlin with flow typing will allow you to use your img variable with type Image after the check, even though it starts out with type Image?:
val img = reader.acquireLatestImage() // this is of type "Image?"
if (img == null) {
Log.d(TAG, "Image is null!")
return
}
// now img is smart-cast to the type Image (non-nullable)
Is it possible to create extension for that?
You won't be able to encapsulate the non-local return inside an extension function, but you could create an extension function for the logging, and then use a plain elvis operator:
fun YourReader.acquireLatestImageOrLog(): Image? {
val img = acquireLatestImage()
if (img == null) {
Log.d(TAG, "Image is null")
}
return img
}
val img = reader.acquireLatestImageOrLog() ?: return
You could even go more general:
fun <T> T?.orLog(message: String): T? {
if (this == null) {
Log.d(TAG, message)
}
return this
}
val img = reader.acquireLatestImage().orLog("Image is null!") ?: return