Set and List overrides Collection methods

Why Set and List interfaces have copy of several methods from Collection interface?

The stdlib code is below. Probably it is worth removing redeclaration and simplify public interfaces?

I can create create issue/PR is you want…

public interface Set<out E> : Collection<E> {
    // Query Operations

    override val size: Int
    override fun isEmpty(): Boolean
    override fun contains(element: @UnsafeVariance E): Boolean
    override fun iterator(): Iterator<E>

    /*....*/
}

/**
 * A generic ordered collection of elements. Methods in this interface support only read-only access to the list;
 * read/write access is supported through the [MutableList] interface.
 * @param E the type of elements contained in the list. The list is covariant on its element type.
 */
public interface List<out E> : Collection<E> {
    // Query Operations

    override val size: Int
    override fun isEmpty(): Boolean
    override fun contains(element: @UnsafeVariance E): Boolean
    override fun iterator(): Iterator<E>

    // Bulk Operations
    override fun containsAll(elements: Collection<@UnsafeVariance E>): Boolean
    /*....*/
}

public interface Collection<out E> : Iterable<E> {
    // Query Operations
    /**
     * Returns the size of the collection.
     */
    public val size: Int

    /**
     * Returns `true` if the collection is empty (contains no elements), `false` otherwise.
     */
    public fun isEmpty(): Boolean

    /**
     * Checks if the specified element is contained in this collection.
     */
    public operator fun contains(element: @UnsafeVariance E): Boolean

    override fun iterator(): Iterator<E>

    // Bulk Operations
    /**
     * Checks if all elements in the specified collection are contained in this collection.
     */
    public fun containsAll(elements: Collection<@UnsafeVariance E>): Boolean
}

I personally like it the way it is. That way it’s easier to see what methods are part of List, Set. Yes, you could always check the methods defined in the parent interface but this way you have all of them in one place.
You could argue that this information is visible in the docs, but I generally prefer to just use IntelliJ “Jump to Declaration” to get this information and only use the docs if I have to. That way I don’t have to leave my IDE.

Just out of interest? Is there any downside to redeclaring methods in interfaces?

This is copy-pasting, so all related problems are here: you need to copy-paste documentation, etc.
I prefer expanding all such methods in IDE (probably with equals/toString/hashCode, etc.) if it is needed (just to cover all possible JVM interfaces).

Moreover, MutableSet doesn’t have copy-pasted methods (and this it cool from my point of view, because we can get a lot of them here).

public interface MutableSet<E> : Set<E>, MutableCollection<E> {
    // Query Operations
    override fun iterator(): MutableIterator<E>

    // Modification Operations

    /**
     * Adds the specified element to the set.
     *
     * @return `true` if the element has been added, `false` if the element is already contained in the set.
     */
    override fun add(element: E): Boolean

    override fun remove(element: E): Boolean

    // Bulk Modification Operations

    override fun addAll(elements: Collection<E>): Boolean
    override fun removeAll(elements: Collection<E>): Boolean
    override fun retainAll(elements: Collection<E>): Boolean
    override fun clear(): Unit
}

However please note, that idea “less unnecessary duplicated code here” is just my opinion. And if there is some logic from Kotlin authors - it is worth for me to know it.

1 Like

My guess is that they are mimicking Java. As for why Java does it, my guess is that they do it in order to provide more specific Javadoc for the overriden methods. It also makes sense conceptually: List and Set overrides the contracts defined by Collection specifying additional requirements on the methods. Repeating them in code makes this more explicit.

Moreover, MutableSet doesn’t have copy-pasted methods (and this it cool from my point of view, because we can get a lot of them here).

Wrong. It’s overriding all the methods defined in MutableCollection, just like how Set is overriding the methods of Collection.

You are right.

MutableSet overrides Set as well as Set overrides Collection.

However MutableSet doesn’t copy methods (they are inherited automatically), but Set has at least four methods, which could be omitted (because they are inherited automatically).

So my question is: why kotlin stdlib has this behaviour for Set/List interfaces?

Not a single method in Set and MutableSet is implicitly inherited from Collection and MutableCollection. All of them are explicitly redefined. This mirrors the definitions in Java, except that Java does not have separate read-only and mutable interfaces.

1 Like