Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Property in interface cannot have a backing field

I am learning Kotlin. My code is as follows:

   interface BaseLogicDecoupler<A : BaseViewNotifier, B : BaseScreenRouter> {

        var notifier: A?
        var router: B?

        fun attachNotifier(notifier: A?) {
            this.notifier = notifier
        }

        fun detachNotifier() {
            notifier = null;
        }

        fun attachRouter(router: B?) {
            this.router = router
        }

        fun detachRouter() {
            router = null;
        }
    }

But when I change it and try to provide an accessor for property like following :

var notifier: A?
    get() = notifier 

It doesn't compile with error saying : Property in interface cannot have a backing field.

From the doc here, kotlin interfaces can provide implementation and can have properties with accessors. Why does the compilation fail?

I am unable to understand the error. What does it say? Can anyone explain in simple terms?

like image 663
Krupal Shah Avatar asked Dec 11 '16 09:12

Krupal Shah


1 Answers

This is an unexpected corner case, kudos to you for finding it.

Let me briefly explain it what goes on. I will use a stripped interface A and class B for the sake of simplicity:

interface A {
    var notifier: Int
}

Normally a var property in a class includes 3 components: a private backing field to store its value, a setter method to write to it and a getter method to read it. But an interface cannot have a field (because live is pain and some math does not add up if it does), so a var property in an interface includes only 2 components: a setter and a getter.

As I outlined above, our interface A has declared 2 methods: a setter and a getter, both without implementations. Let's add some implementations to it:

interface A2 {
    var notifier: Int
        get() {return 1}
        set(v) {}
}

So far, so good. Two open methods with implementations, non of them uses any fields. But what if only one of the implementations is declared?

interface A3 {
    var notifier: Int    //ERROR: Property in an interface cannot have a backing field
        get() {return 1}
        //set(v) {}
}

It turns out that if you specify only a getter, Kotlin also generates a (default) setter for the property. In other words, A3 is similar to A4 here:

interface A4 {
    var notifier: Int
        get() {return 1}
        set(v) {field = v}  //Obviously an error
}

This may be a bug or an intended behaviour. Here is the issue ticket: https://youtrack.jetbrains.com/issue/KT-15193

Possible workarounds:

  • declare an adequate setter as in A2
  • use an abstract class instead of an interface
like image 128
voddan Avatar answered Sep 21 '22 14:09

voddan