1Properties 2========== 3 4Like parameters, properties can be created either with builders or by using convenient helper 5methods: 6 7```kotlin 8val android = PropertySpec.builder("android", String::class) 9 .addModifiers(KModifier.PRIVATE) 10 .build() 11 12val helloWorld = TypeSpec.classBuilder("HelloWorld") 13 .addProperty(android) 14 .addProperty("robot", String::class, KModifier.PRIVATE) 15 .build() 16``` 17 18Which generates: 19 20```kotlin 21class HelloWorld { 22 private val android: String 23 24 private val robot: String 25} 26``` 27 28The extended `Builder` form is necessary when a field has KDoc, annotations, or a field 29initializer. Field initializers use the same [`String.format()`][formatter]-like syntax as the code 30blocks above: 31 32```kotlin 33val android = PropertySpec.builder("android", String::class) 34 .addModifiers(KModifier.PRIVATE) 35 .initializer("%S + %L", "Oreo v.", 8.1) 36 .build() 37``` 38 39Which generates: 40 41```kotlin 42private val android: String = "Oreo v." + 8.1 43``` 44 45By default `PropertySpec.Builder` produces `val` properties. Use `mutable()` if you need a 46`var`: 47 48```kotlin 49val android = PropertySpec.builder("android", String::class) 50 .mutable() 51 .addModifiers(KModifier.PRIVATE) 52 .initializer("%S + %L", "Oreo v.", 8.1) 53 .build() 54``` 55 56## Inline properties 57 58The way KotlinPoet models inline properties deserves special mention. The following snippet of code: 59 60```kotlin 61val android = PropertySpec.builder("android", String::class) 62 .mutable() 63 .addModifiers(KModifier.INLINE) 64 .build() 65``` 66 67will produce an error: 68 69``` 70java.lang.IllegalArgumentException: KotlinPoet doesn't allow setting the inline modifier on 71properties. You should mark either the getter, the setter, or both inline. 72``` 73 74Indeed, a property marked with `inline` should have at least one accessor which will be inlined by 75the compiler. Let's add a getter to this property: 76 77```kotlin 78val android = PropertySpec.builder("android", String::class) 79 .mutable() 80 .getter( 81 FunSpec.getterBuilder() 82 .addModifiers(KModifier.INLINE) 83 .addStatement("return %S", "foo") 84 .build() 85 ) 86 .build() 87``` 88 89The result is the following: 90 91```kotlin 92var android: kotlin.String 93 inline get() = "foo" 94``` 95 96Now, what if we wanted to add a non-inline setter to the property above? We can do so without 97modifying any of the code we wrote previously: 98 99```kotlin 100val android = PropertySpec.builder("android", String::class) 101 .mutable() 102 .getter( 103 FunSpec.getterBuilder() 104 .addModifiers(KModifier.INLINE) 105 .addStatement("return %S", "foo") 106 .build() 107 ) 108 .setter( 109 FunSpec.setterBuilder() 110 .addParameter("value", String::class) 111 .build() 112 ) 113 .build() 114``` 115 116We get the expected result: 117 118```kotlin 119var android: kotlin.String 120 inline get() = "foo" 121 set(`value`) { 122 } 123``` 124 125Finally, if we go back and add `KModifier.INLINE` to the setter, KotlinPoet can wrap it nicely and 126produce the following result: 127 128```kotlin 129inline var android: kotlin.String 130 get() = "foo" 131 set(`value`) { 132 } 133``` 134 135Removing the modifier from either the getter or the setter will unwrap the expression back. 136 137If, on the other hand, KotlinPoet had allowed marking a property `inline` directly, the programmer 138would have had to manually add/remove the modifier whenever the state of the accessors changes in 139order to get correct and compilable output. We're solving this problem by making accessors the 140source of truth for the `inline` modifier. 141 142 [formatter]: https://developer.android.com/reference/java/util/Formatter.html 143