xref: /aosp_15_r20/external/kotlinpoet/docs/properties.md (revision 3c321d951dd070fb96f8ba59e952ffc3131379a0)
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