Functions¶
All of the above functions have a code body. Use KModifier.ABSTRACT
to get a function without any
body. This is only legal if it is enclosed by an abstract class or an interface.
val flux = FunSpec.builder("flux")
.addModifiers(KModifier.ABSTRACT, KModifier.PROTECTED)
.build()
val helloWorld = TypeSpec.classBuilder("HelloWorld")
.addModifiers(KModifier.ABSTRACT)
.addFunction(flux)
.build()
Which generates this:
abstract class HelloWorld {
protected abstract fun flux()
}
The other modifiers work where permitted.
Methods also have parameters, varargs, KDoc, annotations, type variables, return type and receiver
type for extension functions. All of these are configured with FunSpec.Builder
.
Extension functions¶
Extension functions can be generated by specifying a receiver
.
val square = FunSpec.builder("square")
.receiver(Int::class)
.returns(Int::class)
.addStatement("var s = this * this")
.addStatement("return s")
.build()
Which outputs:
fun Int.square(): Int {
val s = this * this
return s
}
Single-expression functions¶
KotlinPoet can recognize single-expression functions and print them out properly. It treats
each function with a body that starts with return
as a single-expression function:
val abs = FunSpec.builder("abs")
.addParameter("x", Int::class)
.returns(Int::class)
.addStatement("return if (x < 0) -x else x")
.build()
Which outputs:
fun abs(x: Int): Int = if (x < 0) -x else x
Default function arguments¶
Consider the example below.
Function argument b
has a default value of 0 to avoid overloading this function.
fun add(a: Int, b: Int = 0) {
print("a + b = ${a + b}")
}
Use the defaultValue()
builder function to declare default value for a function argument.
FunSpec.builder("add")
.addParameter("a", Int::class)
.addParameter(
ParameterSpec.builder("b", Int::class)
.defaultValue("%L", 0)
.build()
)
.addStatement("print(\"a + b = ${a + b}\")")
.build()
Wrapping is explicit¶
In order to guarantee code correctness, starting in version 2.0, KotlinPoet will never replace spaces found in blocks of code with new line symbols, even in cases when the line of code exceeds the length limit. Let’s take this function for example:
val funSpec = FunSpec.builder("foo")
.addStatement("return (100..10000).map { number -> number * number }.map { number -> number.toString() }.also { string -> println(string) }")
.build()
The function will always be printed out like this:
public fun foo() = (100..10000).map { number -> number * number }.map { number -> number.toString() }.also { string -> println(string) }
While the output is correct, the resulting line of code is quite long and hard to read. KotlinPoet
is unable to understand the context of the expression and adjust the formatting for you, but
there’s a trick you can use to declare a breaking space - use the ♢
symbol where you know it’s
safe to optionally wrap the line. Let’s apply this to our example:
val funSpec = FunSpec.builder("foo")
.addStatement("return (100..10000).map { number ->♢number * number♢}.map { number ->♢number.toString()♢}.also { string ->♢println(string)♢}")
.build()
This will now produce the following result:
public fun foo(): Unit = (100..10000).map { number -> number * number }.map { number ->
number.toString() }.also { string -> println(string) }
This is slightly better, but far from perfect - feel free to play around with other formatting
modifiers, such as the standard \n
character which KotlinPoet honors, or the indentation
formatters (⇥
and ⇤
) that the library ships with (see the documentation for CodeBlock
for
more information).
Lastly, imperfect formatting is a known limitation of the library, as KotlinPoet by design prioritizes correctness of generated code over style. If correct and clean formatting is important for your use case, please consider post-processing KotlinPoet’s output using a dedicated code formatter.