# Kotlin incorrectly uses getters for private fields in open classes

**URL:** <https://discuss.kotlinlang.org/t/kotlin-incorrectly-uses-getters-for-private-fields-in-open-classes/30981>\
**Category:** Language Design\
**Created:** [February 26, 2026, 7:25pm UTC](https://discuss.kotlinlang.org/t/kotlin-incorrectly-uses-getters-for-private-fields-in-open-classes/30981 "2026-02-26T19:25:13Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![MooingDuck](https://avatars.discourse-cdn.com/v4/letter/m/ee7513/32.png) [@MooingDuck](https://discuss.kotlinlang.org/u/MooingDuck)\
**Post date:** [February 26, 2026, 7:25pm UTC](https://discuss.kotlinlang.org/t/kotlin-incorrectly-uses-getters-for-private-fields-in-open-classes/30981/1 "2026-02-26T19:25:13Z")

</div>

```auto
@InternalState
open class ImmutableIntIntArrayMap {
    private val map: LongArray
    @Cache private var lastEntryIndex = 0

...

    @Pure fun getLastEntry() = Entry(map[lastEntryIndex])
}

```

My code is using a Purity checker ([GitHub - yairm210/Purity: Kotlin Compiler Plugin for validating Pure and Readonly functions](https://github.com/yairm210/Purity)), which enforces that `@Pure` methods do not call unmarked methods, or modify non-`@Cache` properties. Unfortunately, it fails this case:

> Function “getLastEntry” is marked as Pure but calls non-Pure function “com.unciv.utils.ImmutableIntIntArrayMap.”.
> 
> - If this is in your code, add @Pure annotation to the function.
> - If this is in external code, you can declare it as Pure via the PurityConfiguration in gradle - see [Configuration - Purity](https://yairm210.github.io/Purity/usage/configuration/#handling-external-classes)
> - Since the function called is @Readonly, you can annotate “” as @Immutable so the call will be considered @Pure - see [Advanced usage - Purity](https://yairm210.github.io/Purity/usage/advanced-usage/#marking-variables-as-immutable)

After some experimentation, the crux appears to be a flaw in the Kotlin _compiler_ rather than the purity checker. It appears that since this is an `open class`, the Kotlin compiler is generating a `<get-lastEntryIndex>` method for this field. But it shouldn’t be doing that, since this field is `private`.

[Inheritance | Kotlin Documentation](https://kotlinlang.org/docs/inheritance.html#open-keyword) says “members are final…unless you explicitly mark them as `open`". A later paragraph says “If you override a member of a base class, the overriding member is also open by default.”, but (A) this doesn’t say it applies to fields, and (B) no class overrides this field. It also says “If you want to change this and forbid the subclasses of your class from overriding your implementation, you can explicitly mark the overriding member as `final"`, but obviously I cannot do that since I need this field to be (privately) mutable.

So the generation of this `<get-lastEntryIndex>` method appears to be an error in the Kotlin compiler, with no obvious workaround for this specific case. This would normally be invisible, which is why nobody else has detected it, and is only visible via tools that work with the generated code, such as annotation processors.

---

<div class="post-metadata">

**Author:** ![kyay10](https://avatars.discourse-cdn.com/v4/letter/k/c57346/32.png) [@kyay10](https://discuss.kotlinlang.org/u/kyay10)\
**Post date:** [February 27, 2026, 12:48am UTC](https://discuss.kotlinlang.org/t/kotlin-incorrectly-uses-getters-for-private-fields-in-open-classes/30981/2 "2026-02-27T00:48:05Z")

</div>

Have you tried changing it to `@get:Cache`? getters and setters are “generated” for all properties, but they’re optimized away later (in codegen I believe) for private properties

---

<div class="post-metadata">

**Author:** ![MooingDuck](https://avatars.discourse-cdn.com/v4/letter/m/ee7513/32.png) [@MooingDuck](https://discuss.kotlinlang.org/u/MooingDuck)\
**Post date:** [March 6, 2026, 7:02pm UTC](https://discuss.kotlinlang.org/t/kotlin-incorrectly-uses-getters-for-private-fields-in-open-classes/30981/3 "2026-03-06T19:02:42Z")

</div>

The `@Cache` annotation can only be applied to members, not methods, so I’m extremely dubious that syntax would work, as it appears to attempt to apply the annotation to the getter. I might be able to use `@get::Pure`though, to mark it as pure…
