kotlinpoet icon indicating copy to clipboard operation
kotlinpoet copied to clipboard

Provide a way to add prefix to statements or control flows before newline

Open mscheong01 opened this issue 1 year ago • 1 comments

Is your feature request related to a problem? Please describe. When generating code that includes constructor invocation, we come across the need to end the control flow with },, not just } ex)

val some = SomeClass(
    name = if ( // some condition ) {
        "a"
    } else {
        "b"
    },
    age = 10,
)

we could do

funSpecBuilder
    ~
    .endControlFlow()
    .addStatement(",")
    ~
    .build()

but this would end up as:

}
,

Describe the solution you'd like solutions were proposed by maintainers here: https://github.com/square/kotlinpoet/pull/1503#issuecomment-1487820207 another solution that could maybe work without breaking change is add a withPrefix = "" parameter to FunSpec.Builder.endControlFlow

mscheong01 avatar Mar 29 '23 03:03 mscheong01

So as written I think this is an X-Y problem. What you want is reasonable, but I don't think it's as simple as allowing you to append a comma.

For one, the control flow API and the statement API are designed for Java and not Kotlin. Problems like this are fighting the fact that the API was inherited from a heavily statement-based language whereas Kotlin is heavily expression-based.

I think we need to step back and evaluate what the code body APIs look like from a more fundamental stance and potentially overhaul them completely.

The right way to emit the given example is a statement invoking the constructor of a type with an argument list composed of a series of expressions. You can do this today but it's a little more verbose than it needs to be.

Next, the question is how do you build expressions for syntactical elements like if/else and when. The wrong way that we're forced to use today is through the control flow API, but that API assumes too much. You can already see we've corrupted it today by using it for trailing lambdas and their argument names.

Much of the existing API is used because it gets you visually close to the output you want but doesn't correlate semantically to the type of syntax you're actually emitting. And then when mismatches happen we get issues like this.

JakeWharton avatar Mar 29 '23 04:03 JakeWharton