As I prepare maplibre compose for api stabilizatio...
# library-development
s
As I prepare maplibre compose for api stabilization, I've been reading kotlinlang.org/docs/api-guidelines-backward…. I noticed however that
enum class
and
sealed
aren't called out as compatibility hazards; why not? As long as I have such things in my public api, unless I use the
@Deprecated NonExhaustive = 0
trick, every additional value is a source and runtime breaking change, correct? Is there a common way to deal with such things? For now I'm converting
enum class
to
value class
c
Specificially 'limitations & alternatives'
m
every additional value is a source
yes
and runtime breaking change, correct?
Every bugfix is a runtime breaking change. As long as the new enum is behind a flag, it could be OK for your consumers
Adding a new enum value is binary compatible though, which is the most important compatibility. I guess this is why it isn't called out
c
what timing
💯 2
s
Adding a new enum value is binary compatible though
What do exhaustive when expressions do with that new value? I'd expect an exception of some kind, practically not so different from a method call whose signature changed
Behind a flag
How do I put an enum behind a flag? Oh, if I understand you right, you mean as long as the library doesn't return the new value without some caller-side change?
m
What do exhaustive when expressions do with that new value?
Yep, you'll get a
NoWhenBranchMatchedException
if I understand you right, you mean as long as the library doesn't return the new value without some caller-side change
Yes. Just like you have a function that returns
Int
between 0 and 10 and starts returning 50. If the caller code doesn't expect the new value, it crashes
So it's breaking but I wouldn't classify that as binary-breaking since the code still links correctly
👍 1
s
Yeah, I guess I need to decide to what degree I promise API stability within a single semver major version Probably, code links correctly, compiler guarantees remain true, and behavior promised by the kdoc remains true. Unsure if I want to include source compatibility With that, I can use enums in my public API so long as I trace how they're used and what values get returned when. But, it's easier to just not use them, or use them sparingly
Very similar to data classes in that way; mostly safe as long as constructor and copy are internal, and new properties are added at the end (for component methods)
a
I noticed however that
enum class
and
sealed
aren't called out as compatibility hazards; why not?
They probably should be, please make a YT issue
Another trick: use a sealed class with internal implementations, and expose each as a companion object
val
. Con: it's verbose and you have to remember to keep everything in sync. Pro: internally you can use an exhaustive-when
Copy code
sealed class FooMode {
  companion object {
    @JvmStatic // in case you have non-Kotlin users
    val Alpha: FooMode = AlphaInternal
    @JvmStatic
    val beta: FooMode = BetaInternal
  }

  internal data object AlphaInternal : FooMode()
  internal data object BetaInternal : FooMode()
}