https://kotlinlang.org logo
#getting-started
Title
# getting-started
d

David Kubecka

03/09/2023, 11:56 AM
[java interop] How can I overcome java
@Nullable
which is overly pessimistic? For example, I want to create a shortcut for transactions execution:
Copy code
fun <T> PlatformTransactionManager.execute(block: () -> T): T =
    TransactionTemplate(this).execute { _ -> block() }
This doesn't compile because
execute
is marked as
@Nullable
, therefore the return type must be
T?
. Instead would like it to be
T
, that is whatever
block
returns (which might also be null).
r

Rob Elliot

03/09/2023, 11:59 AM
Can you just throw an exception?
Copy code
fun <T> PlatformTransactionManager.execute(block: () -> T): T =
    TransactionTemplate(this).execute { _ -> block() } ?: throw IllegalStateException("Expected it to be impossible for execute to return null")
d

David Kubecka

03/09/2023, 12:00 PM
As I said, the block can return null. I highlighted that part of my question 🙂
r

Rob Elliot

03/09/2023, 12:00 PM
Oh I see, sorry
r

Riccardo Lippolis

03/09/2023, 12:09 PM
Copy code
fun <T> PlatformTransactionManager.execute(block: () -> T): T =
        TransactionTemplate(this).execute { _ -> block() } as T
this appears to be working, and it removes the warning
d

David Kubecka

03/09/2023, 12:13 PM
Yes, it works, but it generates a warning, not removes one 😞
r

Riccardo Lippolis

03/09/2023, 12:17 PM
oh weird, my IDE did not give any warning there...
image.png
e

ephemient

03/09/2023, 12:24 PM
if you don't want to see the warning on
as T
,
Copy code
@Suppress("UNCHECKED_CAST")
👍 1
r

Riccardo Lippolis

03/09/2023, 12:31 PM
hmm, weird that I don't need that suppression (did not disable that warning in IntelliJ)
d

David Kubecka

03/09/2023, 12:37 PM
Weird indeed. Does it compile without warnings? (btw I also use IDEA)
k

kqr

03/09/2023, 12:39 PM
i feel stupid right now, but if it can return null how can it be
T
?
d

David Kubecka

03/09/2023, 12:40 PM
Plain
<T>
doesn't say anything about its nullability (in contrast to e.g.
<T : Any>
)
k

kqr

03/09/2023, 12:45 PM
ah, thx
d

David Kubecka

03/09/2023, 12:46 PM
I guess the confusion might be about the difference between
T
and
T?
. Well,
T
in this case means the exact return type of the block (preserving nullability), while
T?
might not preserve the nullability, i.e. even if
block
returned non-null then
TransactionTemplate#execute
might still return null. I guess that's a principal deficiency of those java annotations.
r

Riccardo Lippolis

03/09/2023, 1:44 PM
Weird indeed. Does it compile without warnings? (btw I also use IDEA)
yes, no compiler warnings as well... I use Kotlin 1.8.10, btw
d

deive

03/09/2023, 5:04 PM
If you know that what you run in execute never returns a null, then why not use a
!!
?
Copy code
fun <T> PlatformTransactionManager.execute(block: () -> T): T =
    TransactionTemplate(this).execute { _ -> block() }!!
r

Rob Elliot

03/09/2023, 5:05 PM
It can return null if the block returns null. It should have the same type as the block, which may or may not be nullable
d

deive

03/09/2023, 5:07 PM
As in, if
TransactionTemplate.execute
returns T? but you are always running
block: () -> T
then
TransactionTemplate(this).execute { _ -> block() }!!
should be OK?
r

Rob Elliot

03/09/2023, 5:08 PM
i.e.
Copy code
val x: String = tm.execute { "not null" }
val y: String? = tm.execute { if (Random.nextInt(2) == 1) "not null" else null }
e

ephemient

03/09/2023, 5:09 PM
basically a mismatch between Java (where
<T>
is neither nullable nor non-nullable) and Kotlin (where there is such a distinction)
👍 1
Java
@Nullable <T> T foo()
becomes Kotlin
fun <T> foo(): T?
, Java
@NonNull <T> T foo()
becomes Kotlin
fun <T> foo(): T & Any
, and
<T> T foo()
can't be written directly in Kotlin due to platform nullability. none of them result in
fun <T> foo(): T
👍 1
d

deive

03/09/2023, 5:25 PM
I missed part of the original question as well "that is whatever
block
returns (which might also be null)." - this means that block will have to return
T?
so what I said was moot!
r

Rob Elliot

03/09/2023, 5:26 PM
No, the block returns
T
. Whether or not `T`'s concrete type is nullable depends on how you define the block.
Copy code
val notNullBlock: () -> String = { "not null" }
val x: String = tm.execute(notNullBlock)

val nullableBlock: () -> String? = { if (Random.nextInt(2) == 1) "not null" else null }
val y: String? = tm.execute(nullableBlock)
d

deive

03/09/2023, 5:30 PM
yeah, sorry, would you change
PlatformTransactionManager.execute
to be
fun <T : Any>
for a non-nullable version?
r

Rob Elliot

03/09/2023, 5:30 PM
Yes
👍 1
d

deive

03/09/2023, 5:30 PM
Thanks, sorry for my confusion there!
r

Rob Elliot

03/09/2023, 5:32 PM
I missed the important bit too right at the start of the conversation
9 Views