Hello :wave: I’m facing a modularization issue whe...
# android
s
Hello 👋 I’m facing a modularization issue when dealing with sealed interfaces. Here is a dumb example:
Copy code
sealed interface Vehicle

data class Car(val engine: Engine) : Vehicle
data class Bike(val numberOfGears: Int) : Vehicle
Let’s assume we have a whole feature around cars but a different one for bikes (different flow and screens, etc). We’d like split car and bike related files (along with their dto/domain such as the one above) into distinct modules. And the idea would be to have the sealed declaration into a core module where both car and bike modules would depend on. Yet sealed interfaces can’t live outside the package of its implementations. So we can’t go that way. How would you approach this problem? I’ve got few alternatives but none satisfy me. For instance, we could: • Use a simple interface. But we loose our type safety and exhaustivity with when cases 😔 • Force the package name where the sealed interface is declared to be the same as its implementations in other modules and trick the compiler by letting it think it’s under the same package 🤮 • Still go with interfaces but leveraging KSP by generating exhaustive cases to solve the lose of exhaustiveness? Would really love your inputs on that one 🙂
s
Consider the next structure. Code module:
Copy code
sealed interface Vehicle
interface BaseCar: Vehicle
interface BaseBike: Vehicle
Bikes module:
Copy code
sealed interface Bike: BaseBike
data class SportBike(val numberOfGears: Int): Bike
data class ElectricBike(val power: Float): Bike
Cars module:
Copy code
sealed interface Car: BaseCar
data class SportCar(val engine: Engine): Car
This structure allows you to use some advantages of the sealed interfaces, but declare entities in the separate modules. For sure, BaseCar/BaseBike are not sealed and you can declare
Bike2: BaseBike
but you can take as a rule to have a single inheritor from each interface in from the base module over the app.
👀 1
s
It adds a level of indirection but fits exactly what they say in the official doc: “These restrictions don’t apply to indirect subclasses. If a direct subclass of a sealed class is not marked as sealed, it can be extended in any way that its modifiers allow” So, as you said, the implementations directly inherit from an interface but if that interface lives solely for the purpose to inherit from the wanted sealed interface, then we keep the wanted structure. Thanks!
Arf I thought the exhaustive would have worked that way but that’s not the case. So in the end the sealed interface brings nothing as I could directly inherit from the interface
r
With the definition above it should work as expected to do:
Copy code
when (vehicle) {
  is BaseBike -> {}
  is BaseCar -> {}
} //exhaustive
It doesn’t make sense to do a sealed hierarchy when the classes are in different compilation units (gradle modules)