Reputation: 172
I have a code like this:
enum class Player { PLAYER, COMPUTER }
interface BoardCell {
val x: Int
val y: Int
var player: Player?
}
data class Cell(val x: Int, val y: Int, var player: Player?, var value: Int)
data class BoardCellClass(override val x: Int, override val y: Int, override var player: Player?) : BoardCell
data class Request(val board: MutableList<MutableList<BoardCellClass>>? = null, val occupied: MutableList<BoardCellClass>? = null)
class AI(board: MutableList<MutableList<BoardCell>>, private var occupied: MutableList<BoardCell>) {
private var board: MutableList<MutableList<Cell>> = board.map { it.map { Cell(it.x, it.y, it.player, 0) } .toMutableList() } .toMutableList()
}
// in main
val request = call.receive<Request>()
if (request.board == null || request.occupied == null) {
// respond with 403
} else {
val ai = AI(request.board, request.occupied) // Kotlin: Type mismatch: inferred type is MutableList<MutableList<BoardCellClass>>? but MutableList<MutableList<BoardCell>> was expected
// Kotlin: Type mismatch: inferred type is MutableList<BoardCellClass>? but MutableList<BoardCell> was expected
}
But it errors with what is in the comment in the bottom. What am I doing wrong? Clearly, there is an if statement, that catches nullity, so it shouldn't be of type MutableList<MutableList<BoardCellClass>>?
, but MutableList<MutableList<BoardCellClass>>
, no?
Also, MutableList<MutableList<BoardCellClass>>
is compatible with MutableList<MutableList<BoardCell>>
, because it implements that interface, right?
Upvotes: 0
Views: 106
Reputation: 672
MutableList> is compatible with MutableList>, because it implements that interface, right?
No. In your case you can use out
keyword
class AI(board: MutableList<MutableList<BoardCell>>, private var occupied: MutableList<out BoardCell>) {
private var board: MutableList<MutableList<Cell>> = board.map { it.map { Cell(it.x, it.y, it.player, 0) } .toMutableList() } .toMutableList()
}
Clearly, there is an if statement, that catches nullity, so it shouldn't be of type
You can write this code in if (not else) part to compiler understand you in wright way
if (request.board != null && request.occupied != null){
val ai = AI(request.board, request.occupied)
} else {
// respond with 403
}
Upvotes: 1
Reputation: 170899
Also,
MutableList<MutableList<BoardCellClass>>
is compatible withMutableList<MutableList<BoardCell>>
, because it implements that interface, right?
No, it isn't. That's an issue of variance. Searching for "Kotlin variance" will give you many explanations, but the simplest way to see why MutableList<BoardCellClass>
isn't a subtype of MutableList<BoardCell>
is
val list: MutableList<BoardCellClass> = ...
val list1: MutableList<BoardCell> = list // illegal in actual Kotlin!
list1.add(object : BoardCell { ... }) // would add a BoardCell to a MutableList<BoardCellClass>
Then the same logic can be lifted up a level to see that MutableList<MutableList<BoardCellClass>>
isn't a subtype of MutableList<MutableList<BoardCell>>
.
Clearly, there is an if statement, that catches nullity, so it shouldn't be of type
MutableList<MutableList<BoardCellClass>>?
, butMutableList<MutableList<BoardCellClass>>
, no?
That's not quite how Kotlin smart casts work (though the difference isn't relevant most of the time). It's still of type MutableList<MutableList<BoardCellClass>>?
, but if it's used where the required type is MutableList<MutableList<BoardCellClass>>
, it's automatically cast. Here the required type is MutableList<MutableList<BoardCell>>
instead, and so there's no cast inserted and the nullable type shows up in the error message.
Upvotes: 1