https://kotlinlang.org logo
#language-evolution
Title
# language-evolution
g

giso

07/01/2021, 10:10 AM
Hi there, We have several classes in multiple Gradle modules, where we would like to make the constructor only `internal`ly visible to protect against accidental couplings. However most of our DI-wiring happens inside the main application module and therefore, so we are forced to make the visibility
public
. I was wondering how this use case can be fulfilled with Kotlin. Maybe with a compiler plugin, which is only applied to the main module, granting higher visibility? Or more tightly scoped with a method annotation granting only this method a higher visibility? What are you thoughts, or have I overlooked an already present solution?
t

tmg

07/01/2021, 10:16 AM
I don't think that is an issue the language should tackle. You don't need to do the wiring all on the same file, and if a component should just be
internal
then why do you need to wire it outside of the module? whatever depends on it should also be inside that very same module.
regarding this:
Or more tightly scoped with a method annotation granting only this method a higher visibility?
if there is such things as
@VisibleForTesting
there could also be
@VisibleForWiring
I guess.
👌 2
w

wasyl

07/01/2021, 10:49 AM
What kind of DI do you use? In java internal=public so it kind of circumvents that visibility. It’d be a super hacky approach and not very future-proof (e.g. Dagger might move to KSP in the future) unless you write everything manually. But would work, kind of
g

giso

07/01/2021, 11:29 AM
We use Koin and our entire code base is Kotlin-only. Never looked back once 😉
The problem with wiring inside the module is, that the module does not have and should not have dependencies on some of the implementation details of the class dependencies. This would violate the dependency inversion principle.
w

wasyl

07/01/2021, 11:34 AM
I have similar dillema, overall, but for now we use Dagger which actually hid the issue for us. What you can consider is having the concrete types public, but move wiring to an intermediate module which will only depend on the concrete classes as
implementation
and the API for that (interfaces) as
api
. So you’d expose implementations to the wiring module, but in
app
(or elsewhere) you’d depend not on the implementation module, but on the wiring module
g

giso

07/01/2021, 11:40 AM
We also considered a similar approach, extracting the interface and moving the implementation to a higher layer, only usable by the app module. But for some small classes, creating an extra module seems pretty much overkill.
👍 1
Also some colleagues argue, that small functionalities should be kept together in one module and not be scattered between layers, making it harder to navigate.
There is also already something similar, but slightly different to what we need: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-published-api/
w

wasyl

07/01/2021, 11:50 AM
If it’s safety you’re after, I suppose a compiler plugin/custom lint check + Tiago’s
@WiringOnly
or
@VisibleForWiring
annotation solution is the most reasonable
👍 1
g

giso

07/01/2021, 11:57 AM
It’s more expressiveness I am after 😉 But a compiler plugin allowing the module it is applied to, access to annotated classes/functions sounds reasonable. I’ll look into it. Thanks for your input 😊
r

rnett

07/01/2021, 6:20 PM
Another option is to make and use a
RequiresOptIn
annotation. It's more documentation than a hard forbid, but it should prevent inadvertent usages.
☝️ 3
💡 1
g

giso

07/01/2021, 8:45 PM
Nice idea! And the best part is, it comes almost for free.
7 Views