I'm getting a type error that I don't understand, ...
# getting-started
b
I'm getting a type error that I don't understand, and was hoping someone could help me with it.
Copy code
import java.io.File

private fun Format(filename: String): Format? {
    // Never mind the implementation here.
}

fun readFiles(files: Sequence<File>): Map<Format, List<Reader>> =
    files
        .groupBy { getFormat(it.toString()) }
        .filterKeys { it != null }
        .mapValues { it.value.map { f -> f.reader() } }  // ERROR: Type mismatch: inferred type is Format? but Format was expected
I would expect that
filterKeys
gets rid of all the entries with
null
valued keys, doesn't it? Is the issue perhaps that this is not known at compile time?
s
👌
j
Is the issue perhaps that this is not known at compile time?
This
b
Alright, thanks for confirming my suspicion. Fairly new to statically typed languages
j
This is why on collections there are specialized methods like
filterNotNull
which do enforce the nullability in their return type, so it's known at compile time. I don't know if there are equivalents on maps though
b
Ah right. That's good to know. So I might need an entirely different approach here then
j
Copy code
files
    .mapNotNull { file ->
        getFormat(file.toString())?.let { it to file.reader() }
    }.groupBy { it.first }
b
Thanks @Jacob, that looks promising. It's just slightly off but I think I can get that to work. Sounds like less maintenance than my own
filterNotNullKeys
extension function on maps.
m
jacob was close enough, but needs the mapvalues mapped
Copy code
files
    .mapNotNull { file -> getFormat(file.toString())?.let { it to file.reader() } }
    .groupBy({ it.first }, { it.second })
j
@Jacob The values in the grouping that you get from there will be the pairs, which is not ideal. I think you can use an overload of
groupBy
that also has a
valueTransform
so you get the correct values
👍 1
@Michael de Kaste I guess you were quicker 😄
b
Oh I wasn't aware you could map the values with a second lambda 🙂. Nice! Thanks guys
m
@Joffrey I am speed
blob thinking fast 3
e
you can also perform an cast; it can't be checked by the compiler, but as long as you're sure:
Copy code
@Suppress("UNCHECKED_CAST")
fun <K, V : Any> Map<K, V?>.filterNotNullValues(): Map<K, V> = filterValues { it != null } as Map<K, V>
alternately, you could create something like the stdlib's requireNoNulls() for maps
b
Thanks for that additional solution @ephemient. It's a little too advanced for my current level of Kotlin understanding though. Although I do think you might have misunderstood that I want to filter those that have non-null keys and not values, although that's only a minor change 😉.