xref: /aosp_15_r20/external/kotlinpoet/docs/code-control-flow.md (revision 3c321d951dd070fb96f8ba59e952ffc3131379a0)
1*3c321d95SSadaf EbrahimiCode & Control Flow
2*3c321d95SSadaf Ebrahimi===================
3*3c321d95SSadaf Ebrahimi
4*3c321d95SSadaf EbrahimiMost of KotlinPoet's API uses immutable Kotlin objects. There's also builders, method chaining
5*3c321d95SSadaf Ebrahimiand varargs to make the API friendly. KotlinPoet offers models for Kotlin files (`FileSpec`),
6*3c321d95SSadaf Ebrahimiclasses, interfaces & objects (`TypeSpec`), type aliases (`TypeAliasSpec`),
7*3c321d95SSadaf Ebrahimiproperties (`PropertySpec`), functions & constructors (`FunSpec`), parameters (`ParameterSpec`) and
8*3c321d95SSadaf Ebrahimiannotations (`AnnotationSpec`).
9*3c321d95SSadaf Ebrahimi
10*3c321d95SSadaf EbrahimiBut the _body_ of methods and constructors is not modeled. There's no expression class, no
11*3c321d95SSadaf Ebrahimistatement class or syntax tree nodes. Instead, KotlinPoet uses strings for code blocks, and you can
12*3c321d95SSadaf Ebrahimitake advantage of Kotlin's multiline strings to make this look nice:
13*3c321d95SSadaf Ebrahimi
14*3c321d95SSadaf Ebrahimi```kotlin
15*3c321d95SSadaf Ebrahimival main = FunSpec.builder("main")
16*3c321d95SSadaf Ebrahimi  .addCode("""
17*3c321d95SSadaf Ebrahimi    |var total = 0
18*3c321d95SSadaf Ebrahimi    |for (i in 0..<10) {
19*3c321d95SSadaf Ebrahimi    |    total += i
20*3c321d95SSadaf Ebrahimi    |}
21*3c321d95SSadaf Ebrahimi    |""".trimMargin())
22*3c321d95SSadaf Ebrahimi  .build()
23*3c321d95SSadaf Ebrahimi```
24*3c321d95SSadaf Ebrahimi
25*3c321d95SSadaf EbrahimiWhich generates this:
26*3c321d95SSadaf Ebrahimi
27*3c321d95SSadaf Ebrahimi```kotlin
28*3c321d95SSadaf Ebrahimifun main() {
29*3c321d95SSadaf Ebrahimi  var total = 0
30*3c321d95SSadaf Ebrahimi  for (i in 0..<10) {
31*3c321d95SSadaf Ebrahimi    total += i
32*3c321d95SSadaf Ebrahimi  }
33*3c321d95SSadaf Ebrahimi}
34*3c321d95SSadaf Ebrahimi```
35*3c321d95SSadaf Ebrahimi
36*3c321d95SSadaf EbrahimiThere are additional APIs to assist with newlines, braces and indentation:
37*3c321d95SSadaf Ebrahimi
38*3c321d95SSadaf Ebrahimi```kotlin
39*3c321d95SSadaf Ebrahimival main = FunSpec.builder("main")
40*3c321d95SSadaf Ebrahimi  .addStatement("var total = 0")
41*3c321d95SSadaf Ebrahimi  .beginControlFlow("for (i in 0..<10)")
42*3c321d95SSadaf Ebrahimi  .addStatement("total += i")
43*3c321d95SSadaf Ebrahimi  .endControlFlow()
44*3c321d95SSadaf Ebrahimi  .build()
45*3c321d95SSadaf Ebrahimi```
46*3c321d95SSadaf Ebrahimi
47*3c321d95SSadaf EbrahimiThis example is lame because the generated code is constant! Suppose instead of just adding 0 to 10,
48*3c321d95SSadaf Ebrahimiwe want to make the operation and range configurable. Here's a method that generates a method:
49*3c321d95SSadaf Ebrahimi
50*3c321d95SSadaf Ebrahimi```kotlin
51*3c321d95SSadaf Ebrahimiprivate fun computeRange(name: String, from: Int, to: Int, op: String): FunSpec {
52*3c321d95SSadaf Ebrahimi  return FunSpec.builder(name)
53*3c321d95SSadaf Ebrahimi    .returns(Int::class)
54*3c321d95SSadaf Ebrahimi    .addStatement("var result = 1")
55*3c321d95SSadaf Ebrahimi    .beginControlFlow("for (i in $from..<$to)")
56*3c321d95SSadaf Ebrahimi    .addStatement("result = result $op i")
57*3c321d95SSadaf Ebrahimi    .endControlFlow()
58*3c321d95SSadaf Ebrahimi    .addStatement("return result")
59*3c321d95SSadaf Ebrahimi    .build()
60*3c321d95SSadaf Ebrahimi}
61*3c321d95SSadaf Ebrahimi```
62*3c321d95SSadaf Ebrahimi
63*3c321d95SSadaf EbrahimiAnd here's what we get when we call `computeRange("multiply10to20", 10, 20, "*")`:
64*3c321d95SSadaf Ebrahimi
65*3c321d95SSadaf Ebrahimi```kotlin
66*3c321d95SSadaf Ebrahimifun multiply10to20(): kotlin.Int {
67*3c321d95SSadaf Ebrahimi  var result = 1
68*3c321d95SSadaf Ebrahimi  for (i in 10..<20) {
69*3c321d95SSadaf Ebrahimi    result = result * i
70*3c321d95SSadaf Ebrahimi  }
71*3c321d95SSadaf Ebrahimi  return result
72*3c321d95SSadaf Ebrahimi}
73*3c321d95SSadaf Ebrahimi```
74*3c321d95SSadaf Ebrahimi
75*3c321d95SSadaf EbrahimiMethods generating methods! And since KotlinPoet generates source instead of bytecode, you can
76*3c321d95SSadaf Ebrahimiread through it to make sure it's right.
77