Does spreading an array into a vararg parameter copy it or pass the same array? Explain the aliasing/mutation implications, including when the vararg parameter type is `Array<T>` of objects.
answer
- Spread = shallow copy of the array
- Callee array !== caller array (structure isolated)
- Shared element references -> deep mutation leaks
- Primitive varargs copy values, fully isolated
- Can't use vararg array as caller out-param
basics
~20 sSpreading copies the array's elements into a new array that the function receives, so the function's array is a different array. But for object elements both arrays point at the same objects, so mutating an object is visible to both.
solid answer
~40 sThe spread `*arr` produces a **shallow copy**: the callee's `vararg` array is a different array instance from `arr`, so reassigning or sorting elements inside the callee does not mutate your original array's slots. However, the copy is shallow — element **references** are shared, so if elements are mutable objects, mutating an object through either array is visible through the other. For primitive varargs (`IntArray` etc.) values are copied, so there is no shared mutable state. This matters when you assume passing an array 'by reference' protects or shares structural edits: structural edits (index assignment) are isolated by the copy, but deep mutation of shared objects is not. When you spread the *same* array into a function declared `vararg x: T`, you can safely treat the callee's array as private to that call.
code
kotlin · 5 linesfun touch(vararg xs: IntArray) { xs[0][0] = 99 }
val inner = intArrayOf(1, 2)
val outer = arrayOf(inner)
touch(*outer)
println(inner[0]) // 99 -> element (the IntArray) is shared, deep edit visiblego deeper
Knows the function gets an array and can loop it; may not know copy semantics.
Knows spread copies the array so structural edits don't leak back.
Articulates shallow-copy: structure isolated, shared element references, primitive vs reference difference.
Reasons about allocation cost per spread, defensive-copy redundancy, and Array<out T> covariance constraints.
## Spread does a shallow copy When you call `f(*arr)` for `fun f(vararg xs: T)`, the runtime hands the callee a **new array** containing the same elements. This is the standard JVM varargs behavior, and Kotlin's spread follows it. ```kotlin fun mutate(vararg xs: StringBuilder) { xs[0] = StringBuilder("replaced") // structural edit on callee's copy xs[1].append("!") // deep edit on shared object } val a = StringBuilder("a") val b = StringBuilder("b") val src = arrayOf(a, b) mutate(*src) println(src[0]) // "a" -> structural edit NOT visible (separate arrays) println(src[1]) // "b!" -> deep edit IS visible (same object) println(b) // "b!" ``` ## Two layers - **Array identity (structure)**: `*arr` copies the references into a fresh array, so `xs` !== `arr`. Index assignment in the callee (`xs[0] = ...`) does **not** change `arr`. - **Element identity (contents)**: the copy is **shallow** — both arrays hold the **same object references**. Mutating an object (`xs[1].append(...)`) is visible everywhere that object is referenced. ## Primitives are fully isolated For `vararg x: Int` (an `IntArray`), spreading copies the **values**. There are no shared references, so neither structural nor 'deep' mutation leaks back. ## Why this matters - You cannot use a callee's structural edits to a vararg array as an out-parameter mechanism on the caller's array — the copy breaks that. - Defensive copying you might add 'to be safe' is partly redundant for structure but still needed for deep immutability of shared objects. - In hot paths, each spread allocates a new array; combining spreads with literals allocates one combined array. Be mindful of this in tight loops. ## Relationship to `Array<out T>` Reference varargs are typed `Array<out T>` (covariant out-projection at the parameter), which is why you can spread an `Array<String>` into `vararg s: CharSequence`-style situations and why you cannot write arbitrary elements of a supertype back into the original array.
- Does sorting the vararg array inside the function reorder the caller's array?No — the callee operates on a separate copied array, so structural reordering is not visible to the caller.
- Is the copy deep?No, it is shallow: element references are shared, so mutating a referenced object is visible through both arrays.
Like photocopying a contact list: you get your own sheet (edit it freely), but both sheets list the same people — call one and it is the same person.
saying these in an interview costs you the question
- Claiming the function receives the exact same array instance
- Saying mutations of element objects never leak (they do, shallow copy)
- Assuming structural edits in the callee mutate the caller's array
- Confusing primitive (value-copied) with reference (reference-copied) semantics