Hi! I want to write a multiplatform plugin that ge...
# compiler
c
Hi! I want to write a multiplatform plugin that generates overloads for existing functions, similarly to
@JvmOverloads
but with slightly different rules. Ideally, at usage, I'd want something like:
Copy code
@MyCustomOverloads
fun A<T>.foo(other: A<T>): T
to also generate
Copy code
fun A<T>.foo(other: B<T>): T = this.foo(convertToA(other))
fun B<T>.foo(other: B<T>): T = convertToA(this).foo(convertToA(other))
fun B<T>.foo(other: A<T>): T = convertToA(this).foo(other)
where the generated functions are identical to the initial one in all other aspects (same annotations, same kdoc…). My main use-case: as a library author, I'm providing a DSL that has many possible arguments for end-user convenience, but they all call the same function in the end. I want to avoid having to maintain all of these functions myself, so I'd like to get them in the library artifact. It's important that downstream users do not have to configure their build, from their point of view, these overloads shouldn't be different from the real version. I don't know much about compiler plugins; would you say this is feasible with KSP? What would your recommendations be for where to get started implementing something like this?
j
If you are only adding top level functions, ksp could be enough. If you want to add functions to an existing class, you would need a compiler plugin.
y
This is easily doable with KSP, as long as the functions are not inside a class. It's kind of what KSP is built to do really
t
I don't know if it's been solved but it wasn't possible to generate top level functions from FIR/IR compiler plugins. When I tried, the compiler crashed and the problem was somewhere in the compiler code. So, KSP might be the only choice anyway because of that.
j
I don't know if it's been solved but it wasn't possible to generate top level functions from FIR/IR compiler plugins. When I tried, the compiler crashed and the problem was somewhere in the compiler code.
We were generating top level functions in Arrow Inject in the pass with no issues 🤔
t
Interesting, I'll try it again. K2 mode, right?
j
Yeah
t
j
If I remember correctly (as this video was created 2-3 years ago or more), there is a top level function generated there.
t
Maybe you don't go for JS? Here is the issue I think: https://youtrack.jetbrains.com/issue/KT-58886
j
Nop, we didn't add JS
c
In my use-cases, these aren't top-level functions :/ they're overloads in an interface, which default to the main abstract method.
y
Then FIR plugin is the solution, or instead use context parameters
c
Context parameters could be an option, but they're not multiplatform yet, right?
Thankfully since this would only impact first-party modules, if the plugin breaks when using new Kotlin versions, it doesn't impact already published versions, so I guess FIR plugin is safe then. I don't know how to go around writing it though.
y
Well they're not even implemented yet. I think the prototype might be multiplatform though. A smart option would be to have your definition be a base interface of sorts, and then the KSP plugin generates an intermediary interface that adds the overloads and their default impl. Then your first-party implementers use the intermediary interface.
c
I think that works, but I'm not sure how it simplifies the situation? And it makes the generated documentation quite complex, since these interfaces already have a matching abstract class and potentially multiple implementations
j
Well they're not even implemented yet.
They are available since 2.1.20-Beta1
👀 2
Don't remember if I tried them in KMP or JVM tho
c
Oh really?? That's big news 😯
y
Well this allows you to not need context parameters, and instead to use the interface. I don't see how it complicates the documentation that much. The base interface has the base methods. The generated interfaces have the overloads. The implementers simply use the generated interface to "inherit" the overloads.
c
Well, it's one more type in the documentation, which is already massive. But that could be acceptable. It would require the ability for the current module to see methods generated from itself, is this fine with KSP?
y
I believe that is fine. I think pre-existing plugins use that, but don't take my word for it lol
j
They work on KMP
c
👀
they're not mentioned in the blog post
y
On the playground I get "The feature "context parameters" is experimental and should be enabled explicitly. This can be done by supplying the compiler argument '-Xcontext-parameters', but note that no stability guarantees are provided.". Note that the playground still supports context receivers with a deprecation warning lol.
j
they're not mentioned in the blog post
There is no blog post or any announcement about you can try them in 2.1.20
At least for the betas, not sure the final one
additionally, you need to use the latest IDEA from sources, the one stable or eap one does not have syntax highlighting
c
well, thanks for the info, I'm back on the hype train!
j
anyway you have 2.2.0 in the bootstrap repo, if you plan to work with context params I would use those versions because probably they include fixes
c
I probably won't do anything serious with them until they're officially experimental, but I'm very happy to see progress being made, since the KEEP discussion is running in circles a bit
y
All significant KEEP discussions seem to eventually run in circles, so that's a mark of quality IMO! They eventually get resolved when a prototype is released and people play with it. I'm so tempted now to upgrade all my fun projects to that version, but using a not-even-EAP IDE is dissuading me
c
I daily-drive the EAP soooo I'll get it soon I guess
well except that I can't professionally because no versions (even stable) in the past 6 months can run compound run configs, but that's another issue
a
late to the party, but for tasks which only involve generating new declarations, KSP is the most stable of the choices right now
c
Can it generate members in an existing interface? Other commenters here seem to imply it can only generate top-level functions
a
no, because it cannot change any code which already exist (and you need that to add members to an interface) the most common workaround is to just generate extensions (this is what we do in Arrow Optics), or make KSP generate the whole interface (not mix user and generated code)