Return MutableList from extensions on MutableIterables

I’ve noticed that calling extensions such as .filterNotNull() on a MutableList<> will return a normal (read: immutable) List<> instead of a MutableList<> as was called on. It seems that’s the documented behavior, but I think it would make more sense to retain mutability without having to call .toMutableList() again. For example:

This doesn’t work today:

mutableListOf("test", null)
    .filterNotNull()
    .add("another test")

Instead it must be:

mutableListOf("test", null)
    .filterNotNull()
    .toMutableList()
    .add("another test")

Are there other language design decisions at play here that provide reason for returning an immutable list from an extension run on a MutableIterable<>?

It looks like you haven’t quite grasped the way filter works. Filter does not alter the original list, rather it creates a new list based on only reading the original. The extensions are defined on List, not MutableList. If you don’t want unneeded copies, you can work on sequences. If the end result should be mutable then you would end up with:

val result = mutableListOf<String>()
sequenceOf("test", null)
    .filterNotNull()
    .plus("another test")
    .mapTo(result) { it }

or semantically different:

val result = mutableListOf<String>()
sequenceOf("test", null)
    .plus("another test")
    .filterNotNullTo(result)

Of course if you don’t need to do any modification afterwards you would write this:

val result = sequenceOf("test", null)
    .filterNotNull()
    .plus("another test")
    .toList()

This will not create temporary lists. You could of course use asSequence with an existing list. The .plus method is basically the same as the + operator, but when used as operator requires parentheses.

Thanks for the explanation using sequences instead. I do understand that the filter extensions are defined on List and creates a new list as an output. My question instead was more trying to understand why there are not also filter extensions defined for MutableList which will return a new MutableList with the filter applied? This would avoid the need to use sequences in this case, and remove the need to add a .toMutableList() call at the end of the chain if the desired result is another MutableList.

Of course I can add those extensions in my own projects if needed, but I’m interested in the reason that this was omitted from the language.

This is speculation (I don’t have anything to do with the design), but I suspect that part of the reason is that these are functional interfaces and functional programming in its design has no mutable data. No mutable data means no mutable lists.