Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Property getter typed on Supertype instead of Implementation in Kotlin

Tags:

kotlin

Suppose I have two classes, a Baseand a Implwhich extends Base.

package mypackage

open class Base
class Impl : Base()

How would I create a private property for the concrete Impl-Type (for internal use), with a public getter typed as the Base-Type, to achieve polymorphism? My initial approach was like this:

class Test {
    private val myType = Impl()
        get():Base
}

However, the Kotlin compiler complains:

Error:(30, 11) Kotlin: Getter return type must be equal to the type of the property, i.e. 'mypackage.Impl'

Basically, this is what it would look like in plain Java:

public class Test {
    private Impl myImpl = new Impl();

    public Base getBase() {
        return myImpl;
    }
}

How could one achieve this? Am I missing something?

P.S. I am aware of Backing Fields and creating custom methods as a workaround for getter, I was just curious on how to approach this in an elegant, Kotlin style manner.

like image 991
Steffen Funke Avatar asked Aug 06 '15 11:08

Steffen Funke


2 Answers

If the property is private, so will be the getter. In this case, it doesn't matter what type it will have. If you want to have a public property of base type, you'll need to declare it separately:

private val _myType = Impl()

public val myType : Base
    get() = _myType
like image 170
Kirill Rakhman Avatar answered Nov 03 '22 02:11

Kirill Rakhman


You would code this the same as you did in Java, using two different properties. Unless you are ok with Impl never being specialized in the class. So here are many options:

// if you don't need Impl typed as Impl then just hold it as base
class Test1 {
    public val base: Base = Impl()
}

// have both with pointing one reference at the other
class Test2 {
    private val _impl = Impl()
    public val base: Base = _impl
}

// have both, second one is a getter (no real benefit over Test2)
class Test3 {
    private val _impl = Impl()
    public val base: Base
       get() = _impl
}

// use a function to do basically a cast
class Test4 {
    private val _impl = Impl()
    public fun asBase(): Base = _impl
} 

Or don't worry about this other property, any use of grabbing the Impl can hold it as type Base:

class Test5 {
    public val impl: Impl = Impl()
}

// later
val thing: Base = Test5().impl

Maybe you are looking to build this in a way with a common interface to get the base implementation?

open class Base {}

// a common way to get the implementation from within a class
interface Based {
    val base: Base
}

class ImplAbc : Base()
class ImplXyz : Base()

class TestAbc : Based {
    override val base: Base = ImplAbc()
}

class TestXyz : Based {
    private val _impl = ImplXyz()
    override val base: Base = _impl
}
like image 27
Jayson Minard Avatar answered Nov 03 '22 01:11

Jayson Minard