Kotlin Code below works fine
private inline fun <reified T> parseResponse(response: Any): Response<T> =
when (response) {
is T -> { Response(success = response, error = null) }
is GetUserInfoResponseResult.Error -> {
Response(
success = null,
error = Error(response.error.message ?: "", response.error.code?.name ?: "")
)
}
is SetUserInfoResponseResult.Error -> {
Response(
success = null,
error = Error(response.error.message ?: "", response.error.code?.name ?: "")
)
}
else -> throw exception("Failed to process response ")
}
However when I try to combine 2 when clauses
private inline fun <reified T> parseResponse(response: Any): Response<T> =
when (response) {
is T -> { Response(success = response, error = null) }
is GetUserInfoResponseResult.Error, SetUserInfoResponseResult.Error -> {
Response(
success = null,
error = Error(response.error.message ?: "", response.error.code?.name ?: "")
)
}
else -> throw exception("Failed to process response ")
}
In intelliJ I got a red underline for Error in SetuUserInfoResponseResult.Error
saying
classifier Error does not have a companion object and thus must be initialized here
definitions
sealed class GetUserInfoResponseResult {
data class Error(val error: GetUserInfoErrorResponse) : GetUserInfoResponseResult()
data class Success(val success: GetUserInfoSuccessResponse) : GetUserInfoResponseResult()
}
sealed class SetUserInfoResponseResult {
data class Error(val error: SetUserInfoErrorResponse) : SetUserInfoResponseResult()
object Success : SetUserInfoResponseResult()
}
CodePudding user response:
Your current when clause checks whether response is an instance of GetUserInfoResponseResult.Error, or response is equal to the companion object of SetUserInfoResponseResult.Error. The second half is an equality check, because you didn't write is before it. SetUserInfoResponseResult.Error does not have a companion object, hence the error.
Adding the is doesn't fix everything. There are still errors where you try to access response.error.message. This is because smart casts only works when you are checking for a single type. Since you are checking for 2, the compile-time type of response is not smart casted, and is still Any.
You can fix this by introducing a common interface that both error types implements:
interface UserInfoErrorResponseResult {
val error: UserInfoErrorResponse
}
interface UserInfoErrorResponse {
val message: String?
val code: ErrorCode? // I assume you have an ErrorCode class like this
}
Then you can just check for one type - is UserInfoErrorResponseResult - and smart cast would work:
private inline fun <reified T> parseResponse(response: Any): Response<T> =
when (response) {
is T -> { Response(success = response, error = null) }
is UserInfoErrorResponseResult -> {
Response(
success = null,
error = Error(response.error.message ?: "", response.error.code?.name ?: "")
)
}
else -> throw exception("Failed to process response ")
}
Here's an example of how your classes would look like, implementing those interfaces, with some assumptions of how GetUserInfoErrorResponse and SetUserInfoErrorResponse look like.
data class GetUserInfoErrorResponse(
override val message: String?,
override val code: ErrorCode?
): UserInfoErrorResponse
data class SetUserInfoErrorResponse(
override val message: String?,
override val code: ErrorCode?
): UserInfoErrorResponse
sealed class GetUserInfoResponseResult {
data class Error(override val error: GetUserInfoErrorResponse) :
GetUserInfoResponseResult(), UserInfoErrorResponseResult
data class Success(val success: GetUserInfoSuccessResponse) : GetUserInfoResponseResult()
}
sealed class SetUserInfoResponseResult {
data class Error(override val error: SetUserInfoErrorResponse) :
SetUserInfoResponseResult(), UserInfoErrorResponseResult
object Success : SetUserInfoResponseResult()
}
Basically, you should just add override to everything the interface needs, and it should work.
