Search code examples
androidkotlinrx-kotlin

Adding subscribeOn() is changing return type of observable


I've encountered a strange problem which I'm struggling to understand. I have written some code that creates an observable from callable. It compiles fine, but as soon as I specify a scheduler for it it changes the return type and doesn't compile.

Here is the code without the subscribeOn (which compiles):

/**
 * Gets all the room bookings for the specified day
 */
override fun getRoomBookingsForDay(date: Date): Observable<Collection<Model.RoomBooking>> =
        Observable.fromCallable {
            Realm.getDefaultInstance().use { realm ->
                // Get all the bookings that begin and end within the specified date
                val dbRoomBookings =
                        realm.where(DBRoomBooking::class.java)
                                .greaterThan("timeFromUtc", date)
                                .lessThan("timeToUtc", date)
                                .findAllSorted("timeFromUtc")

                if (dbRoomBookings.isEmpty()) {
                    emptyList()
                } else {
                    dbRoomBookings.asSequence().map { dbRoomBooking ->
                        makeRoomBookingModel(dbRoomBooking)
                    }.filterNotNull().toList()
                }
            }
        }

And here is the code with subscribeOn (which doesn't compile):

/**
 * Gets all the room bookings for the specified day
 */
override fun getRoomBookingsForDay(date: Date): Observable<Collection<Model.RoomBooking>> =
        Observable.fromCallable {
            Realm.getDefaultInstance().use { realm ->
                // Get all the bookings that begin and end within the specified date
                val dbRoomBookings =
                        realm.where(DBRoomBooking::class.java)
                                .greaterThan("timeFromUtc", date)
                                .lessThan("timeToUtc", date)
                                .findAllSorted("timeFromUtc")

                if (dbRoomBookings.isEmpty()) {
                    emptyList()
                } else {
                    dbRoomBookings.asSequence().map { dbRoomBooking ->
                        makeRoomBookingModel(dbRoomBooking)
                    }.filterNotNull().toList()
                }
            }
        }.subscribeOn(AndroidRealmSchedulers.realmThread())

The compile time error message is:

Type mismatch.
Required: Observable<Collection<Model.RoomBooking>>
Found: Observable<List<Model.RoomBooking>!>!

Surely, specifying the scheduler shouldn't change the type that is being returned? Any ideas?


Solution

  • I think you have to define the co-variance with the return-type:

    override fun getRoomBookingsForDay(date: Date): Observable<out Collection<Model.RoomBooking>>
    

    Using the out T is the same as ? extends T in Java.

    Alternatively you can make sure to only use the Collection. In your first example the return-type of Observable.fromCallable() is inferred by the return-type of the fun while it is inferred by the return-type of the Callable in the second example. So just declare it directly:

    Observable.fromCallable<Collections<Model.RoomBooking>> { ... }