What's everyone's take on `explicitApi()`? I get t...
# library-development
m
What's everyone's take on
explicitApi()
? I get the intent but feels like it duplicates tools like kotlin binary compatibilty validator or metalava. With kbcv, forgetting to add an
internal
fails the build just like
explicitApi()
would. Same for implicit return types (
fun foo() = ...
) And kbcv saves the ceremony of adding
public
everywhere (in addition to actually tracking the API). In its current state, the only win of
explicitApi()
seems to be that it removes the "unused symbol" warning for potentially unused public API but even that feels borderline counterproductive given that tests should cover most of public API and worst case, it's possible to remove with
@Suppress("unused")
. Thoughts?
t
We use kbcv, but it’s weaknesses are JVM only and that the output it generated only just barely ends up on the “human readable” side of the border (mostly complaints from colleagues on this). It’s strength for sure is that it separates the validation from the code itself. It’s easy to accidentally miss an API change in a code review using only
explicitApi
. We don’t use the latter, though I feel if we would it might help people more easily understand why they broke the API when kbcv flags it.
👍 1
m
Agree with the weaknesses of kbcv but even taking those into account, I feel it's a superset of what
explicitApi
has to offer. Also I'd argue not having several "flavours" of Kotlin is nice. i.e. I get the same visibility behaviour whether writing an app or lib
c
I don't appreciate having to put
public
everywhere. It feels like it's counter-productive to Kotlin's terseness. If
explicitApi
only meant "public declarations must have explicit type declarations", then I would use it.
m
Isn't it the case though?
c
Well you also have to put
public
everwhere
m
as long as it's effectively public
sorry I'm missing something here
explicitApi()
= public API must have
public
keywork in front of them + no return type inferred from an expression
👍 1
c
explicitApi means both: • everything public must be explicitly marked as such • everything public must be explicitly typed I like the second, I don't like the first
🤝 1
3
m
Gotcha 👍 same here
c
Also, I'm not sure how the Kotlin compiler works, but the second is actually great for performance: you could have a simple parser with no validation logic whatsoever that extracts the public function stubs (= the API) and use that as headers to compile the dependent modules, even before the actual source code is compiled. That's how Rust/Cargo works
m
Good point 👍
c
I'm pretty sure the Kotlin compiler doesn't do that though, because it would show up in the Gradle task structure…