I intended to process some data (it's a list of parsed from json objects Nuu
, in the example below I just stubbed the list). To process that collection I pass a consumer println
into the method getAllNuu
that retrieves and parses that "json".
Although, the data I'm receiving from json contains duplicates (based on two [Nuu.lo
, Nuu.la
] of three fields, see overridden Nuu.equals
- generated), so I'd like to merge them together by using extension function Nuu.merge
I don't see any error until I try to compile the code below, then I get:
Error:(7, 5) Kotlin: Type mismatch: inferred type is Collection<Nuu?> but Collection<Nuu> was expected
Why would kotlin infers a collection with nullable objects? Where does it happens?
I would also appreciate any suggestions to make the code better or more kotlin-like.
My environment: kotlinc-jvm 1.3.70 (JRE 12.0.1+12)
Code:
fun main(args: Array<String>) {
getAllNuu { data -> println(mergeNuus(data)) }
}
fun mergeNuus(data: Collection<Nuu>): Collection<Nuu> =
// grouping two same (based on their equals) elements
data.groupingBy { it }
// ^ Error:(7, 5) Kotlin: Type mismatch: inferred type is Collection<Nuu?> but Collection<Nuu> was expected
// merging the equal elemnts into one
.aggregate { _, accumulator: Nuu?, element: Nuu, first ->
if (first)
element
else
accumulator!!.merge(element)
}.values
// supposedly this is a http request which processes
// the retrieved data by passed in consumer 'printout'
fun getAllNuu(printout: (data: Collection<Nuu>) -> Unit) {
val nuuList = listOf(
Nuu(3, "t", 1),
Nuu(5, "6", 2), // say this is a http request
Nuu(7, "a", 3), // just been stubbed with the list
Nuu(3, "a", 4),
Nuu(5, "5", 5),
Nuu(2, "2", 6),
Nuu(3, "t", 7),
Nuu(1, "1", 8),
Nuu(5, "5", 9),
Nuu(2, "2", 10)
)
// processing the data with consumer passed
// from the main method
printout.invoke(nuuList)
}
data class Nuu(
val lo: Int,
val la: String,
val su: Int
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as Nuu
if (lo != other.lo) return false
if (la != other.la) return false
return true
}
override fun hashCode(): Int {
var result = lo
result = 31 * result + la.hashCode()
return result
}
}
// similarity based on equals, and sumup the field 'su'
fun Nuu.merge(other: Nuu) = Nuu(lo, la, su + other.su)
Thanks
In addition to the workaround I gave in comments (.aggregate<Nuu, Nuu, Nuu>
) this also works without specifying any additional types:
data.groupingBy { it }
// merging the equal elemnts into one
.aggregate { _, accumulator: Nuu?, element: Nuu, first ->
val res =
if (first)
element
else
accumulator!!.merge(element)
res
}.values
I really can't see any reason for your code not compiling when this does, and it seems like a compiler bug to me. Of course, I don't see why a bug would happen here either, you aren't doing anything tricky or unusual.