I have a few generic `Map`s of String->Predicat...
# announcements
j
I have a few generic `Map`s of String->Predicate functions of different types. eg, a
Map<String, (Int)->Boolean>
and a
Map<String, (String)->Boolean>
. I'd like to combine them to get a
Map<String, (Any)->Boolean>
, but can't quite figure out how to do so safely. I can safely cast to
Map<String, *>
or
Map<String, Any?>
without an unchecked cast warning, but I can't safely cast to `Map<String, (*)->Boolean>`(compile error) or
Map<String, (Any?)->Boolean>
(unchecked cast)
r
How do you expect that cast to be checked/safe? If you have a
Map<String, (Int) -> Boolean>
and cast it to
Map<String, (Any) -> Boolean>
, what do you expect to happen if you do
map["key"]("fred")
?
Casting generics is never "safe", as they are erased. That doesn't mean you shouldn't do it, just that the IDE can't guarantee things any more, so it's up to you. That's why it's a warning and not an error.
j
ok, but how is it ok to cast to
Map<String, Any?>
?
r
Because there is not generic in
Any?
. That is a concrete type. Function types (like
(Int) -> Boolean
) are generic, and are internally represented as something like
Function<in Int, out Boolean>
.
Anything you can do to
Any?
you can do to
(Int) -> Boolean
. The same isn't true for
(Int) -> Boolean
and
(Any) -> Boolean
as my example showed.
👍 1
r
One approach which is safe is to store the type of the parameter along with the function. You would get
Map<String, Pair<KClass<*>, (Any) -> Boolean>>
and you would need to apply the check for the parameter based on the KClass during runtime to stay safe.
j
The approach I've taken is to move the generics into an encapsulating class that can handle it, and have the outer class layers deal mostly with non-generic types when having to do so "across" the type grain. For example, a
PredicateGenerator<T>
that takes a
<T>
value in its constructor args, but exposes a getPredicate() that returns T/F based on the constructor args. Then I can, for example, AND a bunch of those together without having to know about the "inner" generic instance.