Bagaimana cara menutup cek nol yang tidak perlu yang dihasilkan oleh Kotlin?

9

Pertimbangkan contoh Kotlin minimal berikut:

fun <U> someWrapper(supplier: () -> U): () -> (U) {
    return { supplier() }
}

fun foo(taskExecutor: TaskExecutor): Int {
    val future = CompletableFuture.supplyAsync(someWrapper {
        42
    }, taskExecutor::execute)
    return future.join()
}

@Test
public void shouldFoo() {
    assertThat(foo(), is(42));
}

Saya memiliki aturan cakupan cabang di Jacoco, yang gagal untuk kode di atas, mengatakan 1 dari 2 cabang tidak tercakup di someWrappertelepon. Sayangnya, ini bukan pilihan bagi saya untuk mengecualikan semua kelas dari yang someWrapperdipanggil.

Melihat kode Java yang didekompilasi:

public final int foo(TaskExecutor taskExecutor) {
    Object var10000 = WrappersKt.someWrapper((Function0)null.INSTANCE);
    if (var10000 != null) {
        Object var2 = var10000;
        var10000 = new Foo$sam$java_util_function_Supplier$0((Function0)var2);
    }

    Supplier var3 = (Supplier)var10000;
    Function1 var4 = (Function1)(new Function1(this.taskExecutor) {
        // $FF: synthetic method
        // $FF: bridge method
        public Object invoke(Object var1) {
        this.invoke((Runnable)var1);
        return Unit.INSTANCE;
        }

        public final void invoke(Runnable p1) {
        ((TaskExecutor)this.receiver).execute(p1);
        }

        public final KDeclarationContainer getOwner() {
        return Reflection.getOrCreateKotlinClass(TaskExecutor.class);
        }

        public final String getName() {
        return "execute";
        }

        public final String getSignature() {
        return "execute(Ljava/lang/Runnable;)V";
        }
    });
    CompletableFuture future = CompletableFuture.supplyAsync(var3, (Executor)(new Foo$sam$java_util_concurrent_Executor$0(var4)));
    var10000 = future.join();
    Intrinsics.checkExpressionValueIsNotNull(var10000, "future.join()");
    return ((Number)var10000).intValue();
}

Saya pikir, masalahnya adalah if (var10000 != null)cabang, yang bahkan ditandai oleh IDE menjadi tidak perlu (selalu benar).

Apakah mungkin untuk menyesuaikan kode sedemikian sehingga memungkinkan untuk mencakup semua cabang, mis. dengan memastikan kompiler tidak menghasilkan cek nol tambahan? Saya dapat mengubah kode keduanya foo(..)dan someWrapper(..)selama saya dapat menyediakan lambda yang didekorasi.

Saya menggunakan Kotlin 1.3.50 dan Jacoco 0.8.4.

EDIT.

Satu solusi yang jelas adalah mengekstraksi supplyAsync(someWrapper { ... })ke beberapa kelas utilitas dan mengecualikan kelas itu saja, yaitu .:

fun <U> supplyAsync(supplier: () -> U, executor: TaskExecutor): CompletableFuture<U> {
    return CompletableFuture.supplyAsync(someWrapper { supplier() }, executor::execute)
}

Ini akan cukup baik bagi saya, meskipun saya masih penasaran mengapa cabang ditambahkan oleh Kotlin, di mana tidak perlu ada cabang.

BKE
sumber
Saya dapatkan Type inference failedketika mencoba membuat kompilasi kode sampel Anda. Akan lebih bagus jika Anda bisa memberikan kode sampel yang berfungsi di luar kotak! Misalnya, taskExecutordan controllertidak diketahui.
Enselic
@Enselic menambahkan suntingan kecil untuk menghapus kesalahan yang mengganggu. Saya tidak akan memperluas lebih jauh ke kode lengkap penuh karena ini harus cukup untuk mendapatkan ide.
BKE
1
Melihat bagaimana JaCoCo semakin beradaptasi untuk mendukung Kotlin (lihat github.com/jacoco/jacoco/releases dan mencari "ditambahkan oleh kompiler Kotlin"), saya pikir ini hanyalah celah lain yang akan diperbaiki cepat atau lambat. Jika Anda merasa serius untuk menambah cakupan Anda, saya sarankan melaporkan suatu masalah.
PiotrK

Jawaban:

1

Jika nilai kembali someWrapperhanya dimaksudkan untuk digunakan sebagai contoh Supplier, maka Anda dapat menghapus cek nol yang tidak perlu dengan menggunakan secara eksplisit Suppliersebagai jenis pengembalian.

fun <U> someWrapper(supplier: () -> U): Supplier<U> {
    return Supplier { supplier() }
}
Leo Aso
sumber