How do indexing (`a[i]`) and call (`a()`) syntax map to functions via operator overloading? Show `get`, `set`, and `invoke`.
answer
- a[i] -> get, a[i]=v -> set (value last)
- a() -> invoke
- Multiple indices allowed
- invoke makes objects callable / powers lambdas
- All need `operator`
basics
~10 sa[i] calls a.get(i), and a[i] = v calls a.set(i, v). a() calls a.invoke(). Each must be declared with the operator keyword.
solid answer
~30 sIndex access maps to `get`/`set`: `a[i]` becomes `a.get(i)`; `a[i] = v` becomes `a.set(i, v)` where the assigned value is the **last** parameter. Both support multiple indices — `a[i, j]` is `a.get(i, j)`. The call operator maps to `invoke`: `a()` is `a.invoke()`, `a(x)` is `a.invoke(x)`. `invoke` is what makes lambdas and function types callable and underpins functional-style APIs and DSL builders. All must carry the `operator` modifier. `get` and `invoke` can return any type; `set` typically returns `Unit`. These can be members or `operator` extensions, letting you add index/call syntax to existing types.
code
kotlin · 10 linesclass Config {
private val map = mutableMapOf<String, String>()
operator fun get(key: String) = map[key]
operator fun set(key: String, value: String) { map[key] = value }
operator fun invoke(block: Config.() -> Unit) = apply(block)
}
val c = Config()
c { this["host"] = "localhost" } // invoke with builder lambda
println(c["host"]) // get -> localhostgo deeper
Knows a[i]->get and a()->invoke at a basic level.
Correctly states value-last for set, multi-index support, and what invoke enables.
Connects invoke to function types/lambdas and uses it for DSLs/factories; knows augmented-assignment desugaring touches get+set.
Designs callable/indexable abstractions deliberately (e.g. typed config, DI containers) and weighs clarity vs. cleverness.
## Indexed access: `get` and `set` Kotlin maps square-bracket syntax to the `get` and `set` functions. - **Read:** `a[i]` -> `a.get(i)` - **Write:** `a[i] = v` -> `a.set(i, v)` - **Multiple indices:** `a[i, j]` -> `a.get(i, j)`; `a[i, j] = v` -> `a.set(i, j, v)` For `set`, the **assigned value is always the last argument**. The index arguments come first, in order. ```kotlin class Grid(val w: Int, val h: Int) { private val cells = IntArray(w * h) operator fun get(x: Int, y: Int): Int = cells[y * w + x] operator fun set(x: Int, y: Int, value: Int) { cells[y * w + x] = value } } val g = Grid(3, 3) g[1, 2] = 7 // g.set(1, 2, 7) println(g[1, 2]) // g.get(1, 2) -> 7 ``` `get` may return any type. `set` conventionally returns `Unit`. ## The call operator: `invoke` Declaring `operator fun invoke(...)` makes an instance **callable like a function**: - `a()` -> `a.invoke()` - `a(x)` -> `a.invoke(x)` - `a(x, y)` -> `a.invoke(x, y)` ```kotlin class Adder(val base: Int) { operator fun invoke(x: Int): Int = base + x } val addTen = Adder(10) println(addTen(5)) // addTen.invoke(5) -> 15 ``` This is the same mechanism behind Kotlin's function types: a lambda `{ x: Int -> x + 1 }` is an object whose `invoke` you call when you write `f(x)`. `invoke` is heavily used for **factory-like objects**, **stateful function objects**, and **DSL builders** (an object that you both call and configure). ## Practical notes - All three (`get`, `set`, `invoke`) require the **`operator`** modifier. - They can be **overloaded** (multiple `invoke`/`get` with different parameter lists) and resolved by normal overload rules. - They can be **extensions**, e.g. `operator fun MyType.get(k: String)` to add index syntax to a type you don't own. - Augmented assignment like `a[i] += v` desugars to `a.set(i, a.get(i).plus(v))` when no `plusAssign` applies — combining get, set, and plus.
- In `a[i, j] = v`, what is the parameter order passed to `set`?`a.set(i, j, v)` — indices first in order, the assigned value last.
- How does `invoke` relate to Kotlin lambdas?Function types implement an `invoke` operator; calling `f(x)` on a lambda is `f.invoke(x)`.
saying these in an interview costs you the question
- Putting the assigned value first instead of last in `set`
- Thinking `[]` only supports a single index
- Not knowing `invoke` underlies callable objects/lambdas
- Forgetting `operator` on get/set/invoke