Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin - collection plus() × plusElement() difference

What is difference between plus and plusElement (minus, minusElement) functions over the (immutable) List in practice?

operator fun <T> Collection<T>.plus(element: T): List<T>

fun <T> Collection<T>.plusElement(element: T): List<T>
like image 378
Francis Avatar asked Mar 04 '23 23:03

Francis


1 Answers

Besides plus and minus being operators and therefore simplifiable to + and - respectively, I wanted to share an example, that may make it more clear, why plusElement or minusElement may also make sense to use. Basically that's the case when you do not want the overloaded operator methods to be called (e.g. plus(elements : Iterable<T>)), which may be the case when you are dealing with a list of lists.

Maybe the following samples make that clearer. In the samples all variable assignments show the type they got assigned when calling the respective function and contain the result in the comment at the end of the line. The variable ~ending naming convention is the following:

  • PlusT show calls to plus(element : T)
  • PlusIterable show calls to plus(elements : Iterable<T>)
  • PlusElementT show calls to plusElement(element : T)

Samples:

val someEntry = "some entry"
val listOfSomeEntry = listOf(someEntry)

val los : List<String> = listOf("listOfString")
val lsPlusT         : List<String> = los.plus(someEntry)               // [listOfString, some entry]
val lsPlusIterable1 : List<String> = los.plus(listOfSomeEntry)         // [listOfString, some entry]
val lsPlusIterable2 : List<Any>    = los.plus(listOf(listOfSomeEntry)) // [listOfString, [some entry]]
val lsPlusElementT1 : List<String> = los.plusElement(someEntry)        // [listOfString, some entry]
val lsPlusElementT2 : List<Any>    = los.plusElement(listOfSomeEntry)  // [listOfString, [some entry]]

val lol : List<List<String>> = listOf(listOf("listOfList"))
// the following is basically not really correct as we are now dealing with a list of lists of strings, but it shows that llPlusT and llPlusIterable lead to the same (in this case probably wrong) result..
val llPlusT         : List<Any>          = lol.plus(someEntry)               // [[listOfList], some entry]
val llPlusIterable  : List<Any>          = lol.plus(listOfSomeEntry)         // [[listOfList], some entry]
val llPlusIterable2 : List<List<String>> = lol.plus(listOf(listOfSomeEntry)) // [[listOfList], [some entry]]
val llPlusElement1  : List<Any>          = lol.plusElement(someEntry)        // [[listOfList], some entry]
val llPlusElement2  : List<List<String>> = lol.plusElement(listOfSomeEntry)  // [[listOfList], [some entry]]

As you can see when using + the overloaded variant plus(elements : Iterable<T>) might be used, which will probably make sense in most cases, but may not make sense in some others, e.g. (most of the times) when dealing with a list of lists. Instead of forcing the + to add a list of lists by using + listOf(anotherList), you may rather want to use plusElement (plusElement(anotherList)) or if you are sure you want to add only a single element, you may want to omit plus in favor of plusElement (probably a very rare and very special use case... that would be reflected with variant llPlusElement1).

Finally the plusElement or minusElement make it really clear from the naming that what you pass reflects 1 single item of the list, whereas + leaves that basically open... (you should see that however from the context, which with a list of list is probably not that clear anyways ;-)). And a disclaimer at the end: that should not mean that you should use a list of lists, but just in case you find something like that you have plus/minusElement at hand ;-)

like image 85
Roland Avatar answered Mar 15 '23 22:03

Roland