Assuming I have an interface like this that is par...
# library-development
m
Assuming I have an interface like this that is part of my public API:
Copy code
interface SomeInterface {
  fun function1(param1: Param1)
  fun function2(param2: Param2)
}
Can I somewhat evolve it without having to introduce a new interface name?
Copy code
// Can I evolve it into somthing like this?
interface SomeInterface {
  fun function3(param3: Param3)
  fun function4(param4: Param4)
}
Maybe using default methods? Or do I need to deprecate and find a new name?
a
Depending on your use case, yes you can evolve it like that But that is highly dependent to how the current functions relate to the old ones. I would deprecate the old ones and add new ones
l
You'd be breaking implementation compatibility in all cases. That's where abstract classes might prove more stable I think, if you're careful and use open functions for new ones.
m
I would deprecate the old ones and add new ones
How would that work? If I do this:
Copy code
interface SomeInterface {
  @Deprecated("implement function3 instead")
  fun function1(param1: Param1)
  @Deprecated("implement function4 instead")
  fun function2(param2: Param2)
  fun function3(param3: Param3)
  fun function4(param4: Param4)
}
Then all the implementers now need to implement all 4 functions which isn't great
This is where I was thinking default methods could be useful...
Copy code
interface SomeInterface {
  @Deprecated("implement function3 instead", DeprecationLevel.Error)
  fun function1(param1: Param1) = error("implement function3 instead")
  @Deprecated("implement function4 instead")
  fun function2(param2: Param2) = error("implement function4 instead")
  fun function3(param3: Param3)
  fun function4(param4: Param4)
}
But I'm not 100% sure this works
l
There's no way to not break things without introducing another interface I believe, since you're changing the types
m
I'm ok with "progressive breaking"
If there is a deprecation period
But yea, not 100% sure
l
Would that mean breaking things multiple times?
Is binary compatibility a big concern, or is only source compatibility an issue? Or maybe even this isn't if there are migration facilities (with ReplaceWith or friends)?
m
Is binary compatibility a big concern, or is only source compatibility an issue?
At this point, I'm not 100% sure, I was mainly asking here in case there's a general admitted way to solve this issue. I'll dig
l
Is it for Apollo Kotlin generated code?
m
It's for Apollo Kotlin Adapter interface
We have this
Copy code
@Throws(IOException::class)
  fun fromJson(reader: JsonReader, customScalarAdapters: CustomScalarAdapters): T
where
customScalarAdapters
is actually not needed as a parameter
l
Do other libraries rely on that interface, either by calling it, or implementing it? Or is it purely in application code?
I think I'd do a search on GitHub using the import
m
I'd like to remove
customScalarAdapters
without making it too painful to upgrade
binary breaking is probably ok for a major release
But I'd like to provide a hint to users what changes to do
Ideally an error if anyone implements
fun fromJson(reader: JsonReader, customScalarAdapters: CustomScalarAdapters): T
telling them to remove the last parameter
l
You might hack around using an extension
A deprecated extension
But having it imported by default might be the challenge
I'd try putting it in the companion object
m
The thing it's about implementing, not using it. Kotlinc doesn't complain when trying to implement a deprecated symbol
This compiles fine:
Copy code
interface SomeInterface {
  @Deprecated("use function3 ", level = DeprecationLevel.ERROR)
  fun function1(param1: Int): Int = error("implement function3 instead")
}

class A: SomeInterface {
  override fun function1(param1: Int): Int {
    return 9
  }
}
l
A solution is changing it to an abstract class, and making the deprecated function open
But people will need to call the constructor
So, 2 breakages