question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[Question] Support sealed classes without requiring equals/hash?

See original GitHub issue

I have a view that uses a sealed class ModelProp:

@ModelView(autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT)
class QuestionCard(...) : FrameLayout(...) {
    @ModelProp
    fun setData(data: ObservableData<ProfileQuestion>) {
        this.viewModel.data = data
    }
}

Here’s the sealed class, for reference. It’s basically just to demonstrate the different states we could have:

sealed class ObservableData<out T> {
    data class Data<out T>(val value: T) : ObservableData<T>()
    object Empty : ObservableData<Nothing>()
    data class Error<out T>(val throwable: Throwable?) : ObservableData<T>()
}

If I try to build my project like this, it fails because the model prop ObservableData<> does not override hash code. I didn’t think I would need it since each class inside is its own data class or object, but maybe the compiler isn’t smart enough to notice. So in order for it to work, I had to override them even tho I could leave them empty:

sealed class ObservableData<out T> {
    data class Data<out T>(val value: T) : ObservableData<T>()
    object Empty : ObservableData<Nothing>()
    data class Error<out T>(val throwable: Throwable?) : ObservableData<T>()

    override fun equals(other: Any?): Boolean {
        return super.equals(other)
    }

    override fun hashCode(): Int {
        return super.hashCode()
    }
}

I’m uncertain if anything needs to be changed about Epoxy here, but I wanted to verify that I do in fact have to override these methods, even if all they do is call through to super. If that’s the intended behavior of the library, I can at least make a note in my codebase if I chose to do it this way. I couldn’t find anything in searching the Epoxy repo though so I wanted to close the loop.

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:6 (5 by maintainers)

github_iconTop GitHub Comments

6reactions
dimsuzcommented, Jul 28, 2020

@elihart Actually @IgnoreRequireHashCode is not an optimal solution IMO, it feels more like workaround and relies on discipline to not forget to check that all classes inheriting from this sealed class have proper implementation of equals/hashCode.

The optimal solution would be to explicitly specify this contract in sealed class and let the compiler catch errors. This could be done in the following way:

sealed class Entity {
  abstract override fun equals(other: Any?): Boolean
  abstract override fun hashCode(): Int

  data class EntityImpl1(val v: Int): Entity() // OK
  class EntityImple2(val v2: Int): Entity() // Compilation error: no equals/hashCode
}

I think that this would be better as an official advice in the wiki rather than @IgnoreRequireHashCode which could lead to broken behavior (diffing?) in some cases.

2reactions
elihartcommented, Nov 21, 2019

If I use IgnoreRequireHashCode does that mean they’re still used, though?

Yes, that’s the whole point of it and the difference with DoNotHash

Read more comments on GitHub >

github_iconTop Results From Across the Web

Kotlin sealed classes and hashcode/equals - Stack Overflow
Kotlin Sealed classes do not override the default equals() implementation from the Object Java class. This means that the objects are ...
Read more >
Equals and hash code implementation for sealed classes
I was looking at the generated bytecode and the selaed class itself is not implementing equals and hashcode. When adding the proposed equals...
Read more >
Quiz yourself: The allowable subtypes in sealed classes
Answer. The normal syntax for a sealed type requires that the type define in the permits section the list of allowed direct subtypes....
Read more >
Guide to using sealed classes in Kotlin - LogRocket Blog
Kotlin's sealed classes can be more performant and flexible than enum or abstract classes. Learn how to use them in this tutorial.
Read more >
Sealed Classes and Interfaces in Java 15 - Baeldung
Using the package-private approach, users cannot access the abstract class without also allowing them to extend it:
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found