You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
To better understand pattern usage and to help in decision-making,
69
+
for each pattern occurrence statistics were collected based on open repositories on GitHub.
70
+
67
71
### Use cases targeted by the explicit backing field feature
68
72
69
73
#### Expose read-only supertype
@@ -118,6 +122,23 @@ val city: StateFlow<String> = _city.asStateFlow()
118
122
It is usually more desirable for the primary property to be stored, as in the code snippet above or [this example](https://github.com/wikimedia/apps-android-wikipedia/blob/604007f38e834667f037c475b05f362b92a5575c/app/src/main/java/org/wikipedia/talk/template/TalkTemplatesViewModel.kt#L26-L30).
119
123
However, computed property pattern is also quite popular ([example](https://github.com/jellyfin/jellyfin-androidtv/blob/b46f1acc99fc848abb9ef896c9bb2941e9c6e3ff/playback/core/src/main/kotlin/PlayerState.kt#L75-L88)).
120
124
125
+
##### Convenient type cast without spelling the full type
126
+
127
+
Also, conversion method like `asStateFlow` is used when we want to cast backing property to supertype,
128
+
but we don't want to explicitly spell the full type (which is also was [one of the reasons of introducing `asStateFlow`](https://github.com/Kotlin/kotlinx.coroutines/issues/1973#issuecomment-621660861)):
Apart from rewriting it using explicit backing fields, this use case could be reduced to the simpler form of [previous use-case](#expose-read-only-supertype),
140
+
if [underscore operator in type parameters](#underscore-operator-in-type-parameters) was supported.
141
+
121
142
##### Hide complex value storage logic
122
143
123
144
Sometimes we want to provide a public API for getting the immediate value of a variable,
@@ -232,7 +253,8 @@ Visibility of property must be more permissive than explicit backing field visib
232
253
### Resolution
233
254
234
255
Calls of properties with explicit backing field are resolved to
235
-
- the backing field, if call is made from inside the class (within private scope),
256
+
- the backing field, if property is accessed from the same scope it is declared in
257
+
(actually, follows `private` visibility rules as per [specification](https://kotlinlang.org/spec/declarations.html#declaration-visibility)),
236
258
- getter, otherwise.
237
259
238
260
```kotlin
@@ -250,7 +272,8 @@ fun outside(vm: SomeViewModel) {
250
272
}
251
273
```
252
274
253
-
There is no possibility to call a getter inside the class
275
+
There is no possibility to call a getter instead of field
276
+
when the property is accessed from the same scope it is declared in
254
277
(might be reconsidered in [Future enhancements](#future-enhancements)).
255
278
256
279
### Accessors
@@ -292,6 +315,12 @@ immediately after the backing field is initialized and then returned every time
292
315
293
316
If property with explicit backing field has initializer, it's prohibited to declare accessors.
294
317
318
+
> This use case stands out a little from the rest,
319
+
since it implies the simultaneous existence of two different stored values for one property,
320
+
which sounds dissonant with the current mental image of properties in Kotlin.
321
+
However, this is a case where the desire for consistency gives way to the importance of supporting a popular pattern
322
+
(see [Expose different object](#expose-different-object)).
323
+
295
324
### Accessing field inside accessors and initializers
296
325
297
326
It's possible to access explicit backing field by calling `field` from inside accessors (like it works now for ordinary
@@ -334,6 +363,8 @@ Neither property with explicit backing field:
334
363
* nor explicit backing field itself can be `lateinit` (added to [Future enhancements](#future-enhancements))
335
364
* nor explicit backing field itself can be delegated (added to [Future enhancements](#future-enhancements))
336
365
366
+
It is not prohibited for a top-level property to have an explicit backing field.
367
+
337
368
## Technical details
338
369
339
370
### Grammar changes
@@ -410,7 +441,7 @@ public final StateFlow<String> getCity() {
410
441
### Reflection
411
442
412
443
Callable reference to property with explicit backing field has type `KProperty<V>` (or its subtypes) where `V`
413
-
is type of property (not backing field) regardless of whether it is called inside class or not.
444
+
is type of property (not backing field) regardless of wherever it is accessed from.
414
445
415
446
On JVM backing field can be obtained using [`javaField` extension](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.reflect.jvm/java-field.html).
416
447
@@ -423,11 +454,29 @@ We strive to keep the design simple and uncluttered, so at this point we put asi
423
454
Of course, we may revise some decisions in the future based on community feedback.
424
455
Here is a list of the most obvious future enhancements for the feature:
425
456
426
-
1. Make it possible to access getter instead of explicit backing field when referenced within the scope of visibility of explicit backing field. This is not supported because usually there is no need for calling getter (see [Access backing property inside](#access-backing-property-inside)).
457
+
1. Make it possible to access getter instead of explicit backing field when the property is accessed from the same scope the property is declared in. This is not supported because usually there is no need for calling getter (see [Access backing property inside](#access-backing-property-inside)).
427
458
2. Support other visibilities of explicit backing field (`protected` or `internal`).
428
459
3. Support delegation of explicit backing field or property.
429
460
4. Support `lateinit` explicit backing field.
430
461
5. Support combining mutable explicit backing field and non-mutable property.
431
462
Despite its popularity (see [`var` backing property](#var-backing-property)), this use case is not supported in this proposal, because it is impossible for one property to behave as mutable + nullable and
432
463
at the same time non-mutable and non-nullable.
433
464
6. Add API in Reflection to retrieve information about explicit backing field.
465
+
466
+
### Underscore operator in type parameters
467
+
468
+
It's proposed to make [underscore operator](https://kotlinlang.org/docs/generics.html#underscore-operator-for-type-arguments)
469
+
more powerful and support it in type parameters.
470
+
471
+
This is a separate language feature, yet worth mentioning here,
472
+
as it can help rewrite properties with explicit backing field in a better way in some cases
473
+
(see [Convenient type cast without spelling the full type](#convenient-type-cast-without-spelling-the-full-type)).
474
+
475
+
```kotlin
476
+
val item = field.asStateFlow() // if we don't need read-only wrapper...
477
+
field =MutableStateFlow(ExtremelyLongTypeName.Default)
478
+
479
+
// ...we could rewrite it like that without losing conciseness
480
+
val item:StateFlow<_> // inferred StateFlow<ExtremelyLongTypeName>
481
+
field =MutableStateFlow(ExtremelyLongTypeName.Default)
0 commit comments