The call sites grid[1, 0] and 3 in grid do not compile — find and fix the bug
Grid comes from a library you cannot modify. The two extensions below are meant to power the indexing and membership call sites in main, but neither call site compiles.
Constraints: do not touch Grid, keep both helpers as extensions, and leave the call sites grid[1, 0] and 3 in grid exactly as they are written.
class Grid(val cells: List<Int>, val width: Int) // library class — do not edit
fun Grid.at(x: Int, y: Int): Int = cells[y * width + x]
fun Grid.has(value: Int): Boolean = cells.contains(value)
fun main() {
val grid = Grid(listOf(1, 2, 3, 4), 2)
println(grid[1, 0]) // does not compile
println(3 in grid) // does not compile
}
Find and fix the error.
The operator form resolves only to a conventionally named function marked operator. Rename at to get and has to contains and mark both operator: an extension may carry the keyword, so the library class stays untouched.
- ✗Assuming an operator must be a member and cannot be an extension
- ✗Keeping a free-form name such as
atorhasinstead of the convention - ✗Forgetting that
containsmust returnBooleanforinto work
- →What does the compiler do when the class already has a member
getwith the same signature? - →Which convention would you add so that
for (cell in grid)works as well?
Why it does not compile
An operator in Kotlin is not an arbitrary function. The compiler expands grid[1, 0] into grid.get(1, 0) and 3 in grid into grid.contains(3). The names at and has do not fit the convention — and even with the right names the call will not build without the operator keyword.
The fix
class Grid(val cells: List<Int>, val width: Int) // the library class is untouched
operator fun Grid.get(x: Int, y: Int): Int = cells[y * width + x]
operator fun Grid.contains(value: Int): Boolean = cells.contains(value)
fun main() {
val grid = Grid(listOf(1, 2, 3, 4), 2)
println(grid[1, 0]) // 2
println(3 in grid) // true
}
An extension is allowed to carry operator, so the operator is added to someone else's class with no subclassing and no edit to the library. The convention fixes the signature too: contains must return Boolean, or in will not compile.
Had Grid already declared a member get with the same signature, the member would win — a member always beats an extension.