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