Valeriu Seremet
Valeriu Seremet

Reputation: 568

Android kotlin type inheritance failed

INTRODUCTION:

I created an android project following this example: https://github.com/android/architecture-samples/

I had to add a class that holds the response status(Success/Error) and it's value, in the repository it looks basically like this:

sealed class Result<out R> {
  data class Success<out T>(val data: T) : Result<T>()
  data class Error(val exception: Exception) : Result<Nothing>()
}

It is meant to be better than classic:

class Result<T> (
  val success: Boolean,
  val data: T?,
  val exception: Exception?
)

Because : - In this case the Success result definitely has only data and the Error only exception. - As both Success and Error Message are inheriting from Result, due to Kotlin Smart Casts, the validation looks simpler:

var responce: Result<DataEntity> = dataSource.GetData()
if (responce is Success) {
    doSomethingWith(responce.data)
} else if (responce is Error) {
    throw responce.exception
}

PROBLEM:

All good, but when i'm trying to asynchronously observe data from a local dataSource (using Room lib):

interface TaskDao {
    @Query("SELECT * FROM tasks")
    fun observeTasks(): LiveData<List<TaskEntity>>
}

class SqlLocalDataSource(
    private val taskDao: TaskDao,
    private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO
): LocalDataSource {

    override suspend fun observeTasks(): LiveData<Result<List<TaskEntity>>> = withContext(ioDispatcher) {
            taskDao.observeTasks().map {
            Success(it)
        }
    }
}

It gives me the following Error: Type inference failed. Expected type mismatch: inferred type is LiveData<Result.Success<List<TaskEntity>>> but LiveData<Result<List<TaskEntity>>> was expected

Which is strange because Success inherits from Result

I TRYED:

Upvotes: 1

Views: 734

Answers (2)

Alexey Romanov
Alexey Romanov

Reputation: 170713

It gives me the following Error: Type inference failed. Expected type mismatch: inferred type is LiveData<Result.Success<List<TaskEntity>>> but LiveData<Result<List<TaskEntity>>> was expected

Which is strange because Success inherits from Result

But LiveData<Success<...>> does not inherit from LiveData<Result<...>>. Please read about variance and take into account that LiveData is declared in Java and so can't be covariant.

I don't know why type inference would fail with suspend and work without it, but the problem can be fixed by being more explicit about types:

taskDao.observeTasks().map {
    Success(it) as Result<List<TaskEntity>>
}

Or better, to avoid a cast:

fun <T> success(x: T): Result<T> = Success(x)

taskDao.observeTasks().map {
    success(it)
}

Upvotes: 3

Valeriu Seremet
Valeriu Seremet

Reputation: 568

The Problem was that its not permitted to Use LiveData in a suspend function, after I changed the function to a non suspended the error disappeared :

 override fun observeTasks(): LiveData<Result<List<TaskEntity>>> {
    return taskDao.observeTasks().map {
        Success(it)
    }
}

May be somebody can explain why is it?

Upvotes: 1

Related Questions