I'm making a tiny DSL wrapping an existing builder...
# general-advice
c
I'm making a tiny DSL wrapping an existing builder for a JSON deserializer library, basically adding a few macros to try to make it more declarative. I'm having trouble enabling the bundle of extension methods in the DSL block cleanly. When you're using your own builder class with a
MyBuilder.() -> Unit
parameter, you can obviously have the extensions be members of the builder class to be implicitly available, but I can't figure out how to do that with someone else's without making the end user either import them manually or use a
with
block like below. Does anyone know how I could implicitly let people use this bundle of extensions in the DSL without the
with
block? [Comment = original builder, code = my WIP syntax]
Full code:
I would have made a full DSL to holistically model a JSON-like declaration, but it turns out the "declare a group" method isn't varargs and instead has 16 overloads, so I have to directly invoke it instead of collecting the args to a list and splatting. If anyone knows a workaround for that, please let me know.
c
This is what context parameters are for! They're experimental in 2.2.
Copy code
object CodecBuilderMacros

@JvmInline
value class OptionalFieldMarker(val name: String)

context(_: CodecBuilderMacros)
inline operator fun String.unaryMinus(): OptionalFieldMarker = opt(this)

…

inline fun <T> codec(noinline action: context(CodecBuilderMacros) RecordCodecBuilder.Instance<T>.() -> App<RecordCodecBuilder.Mu<T>, T>): Codec<T> {
    return context(CodecBuilderMacros) {
        RecordCodecBuilder.create(action)
    }
}
😲 1
I would have made a full DSL to holistically model a JSON-like declaration, but it turns out the "declare a group" method isn't varargs and instead has 16 overloads, so I have to directly invoke it instead of collecting the args to a list and splatting. If anyone knows a workaround for that, please let me know.
There isn't a solution for that at the moment (except KSP to generate everything), but it's a question that comes up very often, and the Kotlin team has been experimenting with a few solutions (though no clear winner for now).