Why isn't dropLast available for Iterable

drop and dropWhile are extension functions on Iterable;
while dropLast and dropLastWhile are extension functions on List

What’s the reason behind making dropLast/dropLastWhile an extension function on List, but not the superclass Iterable instead?

(similarly, for takeLast and take)

 


(1.8.21)
dropLast

public fun <T> List<T>.dropLast(n: Int): List<T> {
    require(n >= 0) { "Requested element count $n is less than zero." }
    return take((size - n).coerceAtLeast(0))
}

drop

public fun <T> Iterable<T>.drop(n: Int): List<T> {
    require(n >= 0) { "Requested element count $n is less than zero." }
    if (n == 0) return toList()
    val list: ArrayList<T>
    if (this is Collection<*>) {
        val resultSize = size - n
        if (resultSize <= 0)
            return emptyList()
        if (resultSize == 1)
            return listOf(last())
        list = ArrayList<T>(resultSize)
        if (this is List<T>) {
            if (this is RandomAccess) {
                for (index in n until size)
                    list.add(this[index])
            } else {
                for (item in listIterator(n))
                    list.add(item)
            }
            return list
        }
    }
    else {
        list = ArrayList<T>()
    }
    var count = 0
    for (item in this) {
        if (count >= n) list.add(item) else ++count
    }
    return list.optimizeReadOnlyList()
}

How would you implement those on Iterable?

1 Like

Oh right we don’t know how many elements there are in the Iterable

1 Like

Yeah no way we are going to add then backtrack and remove items from the ArrayList

We won’t be iterating through the iterator twice neither

But then, why isn’t dropLast availabe on Collection?

//Here I simply copied from `List.dropLast` with modified function receiver
//it works just fine!
fun <T> Collection<T>.dropLast(n: Int): List<T> {
    require(n >= 0) { "Requested element count $n is less than zero." }
    return take((size - n).coerceAtLeast(0))
}

I thought about it a little, maybe it is because Set is a subtype of Collection, and Set is conceptually not ordered that it shouldn’t have access to the dropLast, a function conceptually dependent on order, so that we define dropLast under List to prevent Set from accessing it?

But that wouldn’t make sense, because order related extension functions like take, drop, first , last are already available for Set. It is clear that we had “given up” on Set

//conceptually HashSet is not ordered, this is valid in code, but it makes little sense
hashSetOf("a", "b", "c").first() 

With dropLast introduced as an extension function on Collection, such that custom classes that implements Collection would have access to it.