Extension fields in Kotlin

It's easy to write extension methods in Kotlin:

class A { }
class B {
    fun A.newFunction() { ... }
}

But is there some way to create extension variable? Like:

class B {
    var A.someCounter: Int = 0
}

You can create an extension property with overridden getter and setter:

var A.someProperty: Int
  get() = /* return something */
  set(value) { /* do something */ }

But you cannot create an extension property with a backing field because you cannot add a field to an existing class.


No - the documentation explains this:

Extensions do not actually modify classes they extend. By defining an extension, you do not insert new members into a class, but merely make new functions callable with the dot-notation on instances of this class.

and

Note that, since extensions do not actually insert members into classes, there’s no efficient way for an extension property to have a backing field. This is why initializers are not allowed for extension properties. Their behavior can only be defined by explicitly providing getters/setters.

Thinking about extension functions/properties as just syntactic sugar for calling a static function and passing in a value hopefully makes this clear.

However, if you really, really want to do something like this...

As stated above regarding efficiency, an additional backing field added directly to the class is the best way to store data non-derivable from existing non-private members from the class. However, if you don't control the implementation of the class and are dead-set on creating a new property that can store new data, it can be done in a way that is not abysmally inefficient by using separate external tables. Use a separate map that keys on object instances of this class with values that map directly to the value you want to add then define an extension getter and/or setter for this property which uses your external table to store the data associated with each instance.

val externalMap = mutableMapOf<ExistingClass, Int>()

var ExistingClass.newExtensionProperty : Int
    get() = externalMap[this] ?: 0
    set(value:Int) { externalMap[this] = value }

The additional map lookups will cost you - and you need to consider memory leaks, or using appropriately GC-aware types, but it does work.