ran8080
ran8080

Reputation: 41

How do I override sealed class fields?

I created a custom Result field (And not Kotlin's Result) in my service so I can return a message field in Both Success & Failure Cases:

sealed class Result<T> {
    data class Success<T>(val value: T, val message: String) : Result<T>()

    data class Failure<T>(val throwable: Throwable? = null, val message: String) : Result<T>() {
        val isExceptional = throwable != null
        val error: Throwable
            get() = throwable ?: error("Error is undefined in [$this]")
    }
}

Then in another class I called a method that produces this result and wanted to log Result.message

logger.info { "Finished with message [${result.message}]." }

Only, kotlin compiler doesn't recognize "message" since it's not a property of Result directly, but a property of Success and Failure.

I tried to override the message field and define it in Result class. But I get an Error.

Error:(10, 38) Kotlin: 'message' in 'Result' is final and cannot be overridden

So, how can one accesss Result.message without casting the result instance to it's derived implementing class (Success or Failure)?

Upvotes: 1

Views: 5422

Answers (3)

Ege Kuzubasioglu
Ege Kuzubasioglu

Reputation: 6282

1- you can mark them open

open val message: String = ""

2- you can define them abstract

abstract val message: String

Upvotes: 1

Konstantin Raspopov
Konstantin Raspopov

Reputation: 1625

You can declare an abstract property in the Result class:

sealed class Result<T> {
    abstract val message: String
    data class Success<T>(val value: T, override val message: String) : Result<T>()

    data class Failure<T>(val throwable: Throwable? = null, override val message: String) : Result<T>() {
        val isExceptional = throwable != null
        val error: Throwable
            get() = throwable ?: error("Error is undefined in [$this]")
    }
}

Though, your solution is also an option

Upvotes: 3

ran8080
ran8080

Reputation: 41

A clean solution that I found is the following.

While Kotlin does not allow us to override sealed class members. It does allow us to override interface members.

So, I Created a simple interface for the message field, and implemented it from Result class:

interface ResultMessage {
    val message: String
}

sealed class Result<T> : ResultMessage

// Now I'm able to override the message field simply, with no error
data class Success<T>(val value: T, override val message: String) : Result<T>()

data class Failure<T>(val throwable: Throwable? = null, override val message: String) : Result<T>() {
    val isExceptional = throwable != null
    val error: Throwable
        get() = throwable ?: error("Error is undefined in [$this]")
}

Upvotes: 2

Related Questions