5
votes

I am trying to inherit MutableList, and add my own function to it. For example:

class CompositeJob : MutableList<Job> {
    fun cancelAllJobs() {
        for (job in this) {
            job.cancel()
        }
    }
}

But I got the following error:

Class 'CompositeJob' is not abstract and does not implement abstract member
public abstract val size: Int defined in kotlin.collections.MutableList

How can I inherit MutableList, so I can use its original methods like add() and isEmpty(), and add my own one?

Thanks.

5
Point your mouse in CompositeJob class name and do Alt + Enter now those methods are partially implemented for you. BTW implementing MutableList is kinda hassle IMO, will you consider extending to ArrayList<Job> instead? - Enzokie

5 Answers

7
votes

One option other answers don't mention is delegation:

class CompositeJob : MutableList<Job> by mutableListOf() {
    fun cancelAllJobs() {
        for (job in this) {
            job.cancel()
        }
    }
}

is basically equivalent to

class CompositeJob : MutableList<Job> {
    private val impl: MutableList<Job> = mutableListOf()
    override fun size() = impl.size()
    override fun add(x: Job) { impl.add(x) }
    // etc for all other MutableList methods

    fun cancelAllJobs() {
        for (job in this) {
            job.cancel()
        }
    }
}
7
votes

MutableList is an interface - it doesn't implement any of its methods, just declares them. If you want to implement MutableList from scratch, you'll have to implement all 20 of its methods plus the size property, as your error already told you.

You can, however, subclass actual implementations of this interface, for example ArrayList or LinkedList:

class CompositeJob : ArrayList<Job>() {
    fun cancelAllJobs() {
        for (job in this) {
            job.cancel()
        }
    }
}

Edit: If you're just looking to group coroutine Job instances, you should use a parent Job, a SupervisorJob, and CoroutineScope at this point, instead of collecting jobs like this manually.

3
votes

Implementation of all the members is not the only way to achieve what you need.
An easier way is create an extension function like this:

fun MutableList<Job>.cancelAllJobs() {
    this.forEach { it.cancel() }
} 

Now you can call myList.cancelAllJobs() for every MutableList<Job> object.

0
votes

As I have tested you need to make CompositeJob an abstract as error also suggest. After that, you can able to override add() and isEmpty() from MutableList

So your code looks like as below:

abstract class CompositeJob : MutableList<Job> {
override fun add(element:Job): Boolean
  {

  }

override fun isEmpty(): Boolean 
     {

     }
}
-1
votes

If you want to avoid inheritance, or if the concrete class methods are marked final, then you can use composition and redirect all method calls which are not overridden. Here's a template:

class MyMutableList<T> : MutableList<T> {
    private val list = mutableListOf<T>()
    override val size get() = list.size

    // MutableList<T>
    override fun add(element: T): Boolean = list.add(element)
    override fun add(index: Int, element: T) = list.add(index, element)
    override fun addAll(elements: Collection<T>): Boolean = list.addAll(elements)
    override fun addAll(index: Int, elements: Collection<T>): Boolean = list.addAll(index, elements)
    override fun clear() = list.clear()
    override fun remove(element: T): Boolean = list.remove(element)
    override fun removeAll(elements: Collection<T>): Boolean = list.removeAll(elements)
    override fun removeAt(index: Int): T = list.removeAt(index)
    override fun retainAll(elements: Collection<T>): Boolean = list.retainAll(elements)
    override fun set(index: Int, element: T): T = list.set(index, element)

    // List<T>
    override fun contains(element: T): Boolean = list.contains(element)
    override fun containsAll(elements: Collection<T>): Boolean = list.containsAll(elements)
    override fun get(index: Int): T = list.get(index)
    override fun indexOf(element: T): Int = list.indexOf(element)
    override fun isEmpty(): Boolean = list.isEmpty()
    override fun iterator(): MutableIterator<T> = list.iterator()
    override fun lastIndexOf(element: T): Int = list.lastIndexOf(element)
    override fun listIterator(): MutableListIterator<T> = list.listIterator()
    override fun listIterator(index: Int): MutableListIterator<T> = list.listIterator(index)
    override fun subList(fromIndex: Int, toIndex: Int): MutableList<T> =
        list.subList(fromIndex, toIndex)
}

...of course, this might add an additional layer of indirection, possibly affecting list performance with a slight overhead.