Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin and RxJava - Why is my Single.zip() not compiling?

Tags:

kotlin

rx-java

I'm going a little crazy here. I'm trying to create an Observable<BigDecimal> extension function (against RxJava 2.x) to emit the average of the emissions, but I'm getting a compile error with the Single.zip() function. Does anybody have any ideas what I'm doing wrong? I tried to be explicit with all my types too and that didn't work...

import io.reactivex.Observable import io.reactivex.Single import java.math.BigDecimal   fun Observable<BigDecimal>.sum() = reduce { total, next -> total + next }  //compile error fun Observable<BigDecimal>.average() = publish().autoConnect(2).let {     Single.zip(it.sum().toSingle(), it.count()) {         sum, count -> sum / BigDecimal.valueOf(count)     } } 

enter image description here

like image 723
tmn Avatar asked Mar 06 '17 21:03

tmn


People also ask

Does RxJava work with Kotlin?

RxJava is a library that provides an Rx framework for Java-based projects such as Android apps. RxJava can be used even when using the Kotlin language for app development.

Is RxJava deprecated?

RxJava, once the hottest framework in Android development, is dying. It's dying quietly, without drawing much attention to itself. RxJava's former fans and advocates moved on to new shiny things, so there is no one left to say a proper eulogy over this, once very popular, framework.


2 Answers

Type inference mostly does not work for rxJava2. It's not a type inference problem actually. Kotlin usually generates extension methods to that replaces SAM with kotlin functional types, but this technic does not work for overridden methods for some reason.

More details here https://youtrack.jetbrains.com/issue/KT-13609

As an option, you could try to specify types for lambda arguments

fun Observable<BigDecimal>.average() = publish().autoConnect(2).let {     Single.zip(it.sum().toSingle(), it.count(), BiFunction {         sum: BigDecimal, count: Long ->         sum / BigDecimal.valueOf(count)     }) } 
like image 151
Stepango Avatar answered Sep 20 '22 06:09

Stepango


Type inference is failing for some reason, there must be somehow multiple combinations of types that could be inferred in this context.

You can specify the types explicitly with a more traditional (and unfortunately more verbose) syntax, like this:

fun Observable<BigDecimal>.average() = publish().autoConnect(2).let {     Single.zip(it.sum().toSingle(), it.count(), BiFunction<BigDecimal, Long, BigDecimal> {         sum, count ->         sum / BigDecimal.valueOf(count)     }) } 

Update:

I've just found out while working on a similar problem that the actual problem here is that Kotlin isn't able to infer which Single.zip overload you're trying to call. From the official documentation:

If the Java class has multiple methods taking functional interfaces, you can choose the one you need to call by using an adapter function that converts a lambda to a specific SAM type. Those adapter functions are also generated by the compiler when needed.

So it turns out that using the more explicit SAM constructor solves this in itself, and gives you type inference back (basically, my previous answer was using a longer syntax than was actually required):

fun Observable<BigDecimal>.average(): Single<BigDecimal> = publish().autoConnect(2).let {     Single.zip(it.sum().toSingle(), it.count(), BiFunction {         sum, count ->         sum / BigDecimal.valueOf(count)     }) } 
like image 28
zsmb13 Avatar answered Sep 19 '22 06:09

zsmb13