spleenjack
06/30/2023, 8:57 AMmapOfNotNull
in stdlib to build a map from a list of nullable pairs from which only non-null pairs will be taken? There are two other functions (listOfNotNull
and setOfNotNull
) here and it seems quite reasonable to have a similar function for maps for the sake of consistency. I know that you can just write your own implementation, but it’s unlikely that you will do it most optimal and correct way (just for example, you should probably not forget about inlined mapOfNotNull() = emptyMap()
, and etc).Rob Elliot
06/30/2023, 9:00 AMfun <K, V : Any> Map<K, V?>.filterNotNullValues(): Map<K, V>
- I seem to end up writing that quite a lot.Michael de Kaste
06/30/2023, 9:01 AMMichael de Kaste
06/30/2023, 9:01 AMJoffrey
06/30/2023, 11:00 AMvararg
argument to act as builders for hardcoded lists of things. When you use listOf(item1, item2)
you provide those variables by hand. Those variables may be nullable, so a listOfNotNull(item1, item2)
kinda makes sense. However, for maps, you usually don't provide pair variables on the vararg but rather keys and values, and build non-nullable pairs out them on the spot with to
, so I see little benefits of have such mapOfNotNull()
function. In cases where you have an actual list of pairs already, you would instead transform the list like filterNotNull().toMap()
spleenjack
06/30/2023, 11:20 AMfun createByBuildMap(requestId: String?) = buildMap {
this["appName"] = "foo"
if (requestId != null) {
this["requestId"] = requestId
}
}
fun createByListOfNotNull(requestId: String?) = listOfNotNull(
"appName" to "foo",
requestId?.let { "requestId" to it },
).toMap()
// naive implementation only for example
fun <K, V> mapOfNotNull(vararg pairs: Pair<K, V>?) = pairs.filterNotNull().toMap()
fun createByMapOfNotNull(requestId: String?) = mapOfNotNull(
"appName" to "foo",
requestId?.let { "requestId" to it },
)
Joffrey
06/30/2023, 4:08 PMbuildMap
variant looks at least as clear as the mapOfNotNull
variant to me. That's technically just personal preference, and I would probably use put
over this[...] = ...
, but the case for a mapOfNotNull
doesn't seem that strong with this use case (if the goal is just to replace an if
with a let
).Joffrey
06/30/2023, 4:09 PMrequestId
key to exist in the map when its value is not provided? For your use case it would seem just more obvious/simpler to use a Map<String, String?>
and just have mapOf("appName" to "foo", "requestId" to requestId)
. At least, this holds for key-based access of the map (but that's what maps are for). If your goal is to iterate the map's pairs, then probably a list would be more suited in the first place.spleenjack
06/30/2023, 4:19 PMthis["foo"] = "bar"
(or put("foo", "bar")
and a lot of if-conditionsJoffrey
06/30/2023, 4:22 PMif
for multiple entries, etc. rather than trying to cram everything in one vararg function call.
But if that's a serialization use case, why not use a data class for this instead? And use the serialization library's feature to include or not optional keys?spleenjack
06/30/2023, 4:34 PMlistOfNotNull
and someone wants it in stdlib. Here we can give him the same advices (“just use `listOf(…).filterNotNull()`“). I think that would be weird 🙂 There are many examples of using constant lists, and exactly the same number of use-cases with using constant maps. These things are very similar.spleenjack
06/30/2023, 4:36 PMlistOf/setOf/mapOf
triplet but we have listOfNotNull/setOfNotNull
duplet and that’s strangespleenjack
06/30/2023, 4:37 PMJoffrey
06/30/2023, 4:56 PM?.let {}
). On the other hand, the elements in a list are the main entities of the list, not just a construction tool, so wanting to filter out nullable values at construction is not really far fetched. And also I would argue that with the (newer) builder DSLs we don't even need those anymore either.
Secondly, it's quite rare to deal with lists of nullable element types. We usually don't want nulls in lists or sets, so we'd rather not put the element there in the first place. On the other hand, a map is often accessed by key, and the absence of key yields a null value. A get
call in a map returns a nullable type even if the map has a non-nullable value type. When used this way, it doesn't make a difference whether the key is present or not. So the use case of wanting to conditionally insert a key depending on whether the value is present is not really justified so far. Serialization may be an argument, but it doesn't look like a map is the correct representation in this case.spleenjack
06/30/2023, 8:30 PMJoffrey
06/30/2023, 9:09 PM