-
-
Notifications
You must be signed in to change notification settings - Fork 65
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Kotlin190 #504
Conversation
@vlsi You seem to be knowledgeable about Kotlin's type system. At least more knowledgeable than I am. Do you have a suggestion on how to solve this problem? |
The case is as follows:
@NonNullApi
package net.jqwik.api;
public interface Arbitrary<T> { effectively means public interface Arbitrary<@NotNull T> {
In other words, public interface Combinator2<T1, T2> {
// I believe @NotNull is not needed as "R" is not nullable because there's package-level NotNullApi
<R> Arbitrary<R> as(F2<T1, T2, @NotNull R> combinator); At the same time, in Kotlin, type variables are nullable by default. In other words, the following Kotlin declaration means fun <T1, T2, R> combine(
a1: Arbitrary<T1>,
a2: Arbitrary<T2>,
filter: ((T1, T2) -> Boolean)? = null,
combinator: (v1: T1, v2: T2) -> R
): Arbitrary<R> = if (filter == null) {
Combinators.combine(a1, a2).`as`(combinator)
} That is why So the solution depends on your intention for // T1: Any means "T1 is non-nullable"
fun <T1: Any, T2: Any, R: Any> combine(
a1: Arbitrary<T1>,
a2: Arbitrary<T2>,
filter: ((T1, T2) -> Boolean)? = null,
combinator: (v1: T1, v2: T2) -> R
): Arbitrary<R> = if (filter == null) {
Combinators.combine(a1, a2).`as`(combinator)
} Does that make sense? |
In most cases - one exception is I just noticed that removing
from compiler options will allow me to leave the Kotlin code as is. I'm not sure though, how much type-safety I'm gonna lose on the Kotlin side then. |
At the same time, sometimes you have For instance: <R> Arbitrary<R> as(F2<T1, T2, @NotNull R> combinator); It suggests that "sometimes the third type parameter of F2 might be nullable". In other words, you might want replace public interface F2<T1, T2, R> { with // org.jspecify:jspecify:0.3.0
import org.jspecify.annotations.Nullable;
// Allow T1, T2, R to be nullable depending on the actual usage sites
public interface F2<@Nullable T1, @Nullable T2, @Nullable R> |
is |
I am afraid, the way to go is to declare // Allow usage with nullable type
interface Arbitrary<@Nullable T> {
} Even though you might "suppress" the warnings in jqwik's module, the very same issues would appear for all Kotlin users. |
JetBrains See |
Thanks for all the clarification @vlsi My new strategy:
|
Doing step-by-step migration on main |
Overview
Make jqwik
kotlin
module work with Kotlin 1.9.0The problems are mostly about arbitrary types. While the Java implementation does not differentiate between nullable and non-nullable types, the Kotlin compiler assumes that they are non-nullable and deferes
T & Any
whereas the Kotlin functions use justT
since the incoming arbitraries (or functions or whatever) could be nullable or non-nullable.Problem
How to handle this type mismatch correctly?
I hereby agree to the terms of the jqwik Contributor Agreement.