Reputation: 1077
I'm trying to put several functions in a map. The idea is to have: Map<String, [function]>
.
The code is as follows:
class UserIdQueriesHandler {
val strategy: Map<String, KFunction2<@ParameterName(name = "id") String, @ParameterName(name = "options") Array<Options>, Answer>> =
mapOf( // the compiler complains here
"d" to ::debt,
"p" to ::currentProduct
)
fun debt(id: String, options: Array<DebtOptions>): UserDebt = UserDebt(isPresent = true, amount = 0.0)
fun currentProduct(id: String, options: Array<CurrentProductOptions>): UserProducts = UserProducts(products = emptyList())
}
enum class DebtOptions : Options { BOOL, AMOUNT }
enum class CurrentProductOptions : Options { ALL, PRINT, DIGITAL, ENG, HEB, TM }
data class UserDebt(val isPresent: Boolean, val amount: Double) : Answer
data class UserProducts(val products: List<Int>): Answer
Answer
and Options
are simple kotlin interfaces:
interface Answer
interface Options
Compiler output:
Type inference failed. Expected type mismatch:
required:
Map<String, KFunction2<@ParameterName String, @ParameterName Array<Options>, Answer>>
found:
Map<String, KFunction2<@ParameterName String, {[@kotlin.ParameterName] Array & [@kotlin.ParameterName] Array }, Answer>>
Upvotes: 0
Views: 212
Reputation: 89548
Since an Array
can be both read and written, its type parameter is invariant. This makes it so that you can't assign an Array<DebtOptions>
to a variable that has the type of Array<Options>
. The former isn't a subtype of the latter, because it would allow you to put other elements in the array that are Options
, but not DebtOptions
, leading to problems to code that has a reference to this array as an Array<DebtOptions>
.
A solution would be to make your functions accept Array<Options>
, if you can.
val strategy: Map<String, KFunction2<String, Array<Options>, Answer>> =
mapOf(
"d" to ::debt,
"p" to ::currentProduct
)
fun debt(id: String, options: Array<Options>): UserDebt = ...
fun currentProduct(id: String, options: Array<Options>): UserProducts = ...
You could combine this with using the nicer functional type instead of a KFunction2
:
val strategy: Map<String, (String, Array<Options>) -> Answer> = ...
Upvotes: 1
Reputation: 170745
The type of strategy
says functions you put into it can accept any Array<Options>
as the second argument, which debt
and currentProduct
can't.
The simplest workaround would be to change their argument type to Array<Options>
(or List<Options>
; they probably don't need to mutate it!) and fail at runtime if wrong options are passed or ignore them.
Variance section in the documentation is also relevant.
Upvotes: 1