pass list of interface that is used in a Class to constructor

by trfalgarlaw   Last Updated June 13, 2019 08:26 AM

I have two interfaces that have 2 different variables. I created a class that implements these 2 interfaces. Now I want to pass a list of the first interface to a constructor of another class and use its property (from both interfaces). So far I succeeded to have the constructor but I couldn't find how to pass the list of params

interface A {
    var name: String
}

interface B {
    var job: String
}

class C(
    override var name: String,
    override var job: String
) : A, B

class D() {
    private fun getList() {
        val list: List<A> = arrayListOf(
            C("user1", "job1"),
            C("user2", "job2"),
            C("user3", "job3")
        )
        // I want to init E() my constructor here 
    }
}

class E<T>(val list: List<T>) where T : A, T: B {
    fun display() {
        list.forEach {
            println("my name is ${list.get(i).name} and I am a ${list.get(i).job}")
        }
    }
}
Tags : kotlin


Answers 2


If I understood correctly your question, Your code needs just a little improvement to solve your problem

interface A {
    var name: String
}

interface B {
    var job: String
}

class C(
    override var name: String,
    override var job: String
) : A, B

class D {
    fun getList(): E<C> = E(
        arrayListOf(
            C("user1", "job1"),
            C("user2", "job2"),
            C("user3", "job3")
        )
    )
}

class E<T>(val list: List<T>) where T : A, T: B {
    fun display() {
        // for (i in 1..10) will throw OutOfBoundsException
        list.forEach {
            println("my name is ${it.name} and I am a ${it.job}")
        }
    }
}

// to test
fun main(args: Array<String>) {
    D().getList().display()

    /* will prints
       my name is user1 and I am a job1
       my name is user2 and I am a job2
       my name is user3 and I am a job3 */
}
Scrobot
Scrobot
June 13, 2019 08:03 AM

Expanding a bit on the answer that @Scrobot gave.

In short terms you cannot do what you are trying to do. When you specify List<A> as the type, you leave out information about if the elements in your list implements interface B.

If you could do what you try to do, you could very easily break your code by doing things like:

class PureA : A {
    override var name: String
}

val list: List<A> = arrayListOf(
    C("user1", "job"),
    PureA("user2")
)

// The following line will not work, and for good reason
// E(list)

If the last line worked you would basically break your code. PureA is a valid element in a List of As, but it is not of E.

The following is a lot closer to what you intend to do:

// Doesn't work fully
class D<T> where T: A, T: B {
    private fun getList(): E<T> {
        val list: List<T> = arrayListOf<T>(
            C("user1", "job1"),
            C("user2", "job2"),
            C("user3", "job3")
        )

        E(list)
    }
}

I could not see a complete way to finalize what you what to do. I assume that you want to allow future classes that implement A and B too. Only way I've found that would work is:

interface AB : A, B

class C(
        override var name: String,
        override var job: String
) : AB

class D {
    private fun getList() {
        val list: List<AB> = arrayListOf(
            C("user1", "job1"),
            C("user2", "job2"),
            C("user3", "job3")
        )

        E(list)
        // I want to init E() my constructor here
    }
}

Which is a perfectly good solution, even though it gives you more interefaces. But that is usually perfectly fine :)

Rohde Fischer
Rohde Fischer
June 13, 2019 08:25 AM

Related Questions


Updated March 12, 2019 21:26 PM

Updated September 11, 2018 16:26 PM

Updated August 20, 2018 16:26 PM