edrd
10/11/2020, 10:20 PMSymbolProcessor#init
like annotation processor interfaces do? Having init
and process
in the same interface forces the declaration of `var`s to reference arguments from init
for later usage in process
. IMO a better approach would be a factory/provider interface:
// ServiceLoader would load this instead
interface SymbolProcessorFactory {
// same args passed to init
fun create(codeGenerator: CodeGenerator, ...): SymbolProcessor
}
interface SymbolProcessor {
fun process(...)
fun finish()
}
Although it would be a little more work to implement, there are some pretty concise ways of doing it:
class Processor(private val codeGenerator: CodeGenerator) : SymbolProcessor {
override fun process(...) { ... }
object Factory : SymbolProcessorFactory {
override fun create(codeGenerator: CodeGenerator, ...) = Processor(codeGenerator)
}
}
This would allow full immutability.Zac Sweers
10/12/2020, 1:18 AMlateinit var
properties are effectively immutable and can be guarded with visibility if you're worried about others touching them, seems like an unnecessary amount of abstraction just to be able to use val
in a class that has pretty clear guarantees about its lifecycle within the compilationedrd
10/12/2020, 1:27 PMinit
won't be called more than once, which I imagine could happen when compiling multiple modules or something like that. Besides usage of var
(which can be reassigned, even with lateinit
), this would be a problem in case I did some heavy processing inside init
, so things such as isInitialized
start to appear.
The proposed abstraction would eliminate these concerns with a contract that is clear and allows immutability. Besides that, it's a common pattern to deal with runtime dependencies and avoid temporal coupling.edrd
10/12/2020, 1:32 PMedrd
10/12/2020, 1:34 PMZac Sweers
10/13/2020, 2:35 AMThe problem is that I have to read the documentation to know for sure that theIs the function being namedwon’t be called more than onceinit
init
not enough context?
I think you’re overthinking this a bit. Compilers have lifecycles, I don’t think it’s unreasonable for KSP to expose those callbacks.edrd
10/16/2020, 3:33 PMclass Processor : SymbolProcessor {
private lateinit var codeGenerator: CodeGenerator
fun init(codeGenerator: CodeGenerator, ...) {
this.codeGenerator = codeGenerator
}
fun process(...) {}
}
(proposed)
class Processor(private val codeGenerator: CodeGenerator) : SymbolProcessor {
fun process(...) {}
object Provider : SymbolProcessorProvider {
override fun create(codeGenerator: CodeGenerator, ...) = Processor(codeGenerator)
}
}