I have `fun <T> foo1(vararg elements: Iterab...
# getting-started
y
I have
fun <T> foo1(vararg elements: Iterable<T>) = /* ... */
I also have
fun foo2(vararg elements: List<Bar>)
what exactly happens when I call
foo1(*elements)
from within
foo2
? what does the spread operator do here? is this zero cost?
y
You can always decompile the bytecode. I believe theres a
Show Kotlin Bytecode
option in IntelliJ, but I personally just use the cfr decompiler manually. Regardless, I believe it ends up creating a new array
y
oh wow now I'm very happy I asked this question, never knew about this decompiler.
it clearly says it calls
Arrays.copyOf
. not zero cost
well... in a non-garbage collected language
I've shown my ignorance of GC languages here before
y
I vaguely remember some discussion that if you pass the array directly like:
Copy code
foo1(elements = elements)
maybe it doesn't copy then, but I haven't checked
y
that does not seem to be the case here.
c
The reason it copies is because arrays are mutable, but this would be _very weird_:
Copy code
class A(
    val a: Array<Int>,
)

fun A(vararg a: Int) = A(*a)

val data = arrayOf(1, 2, 3)
val a = A(*a)
data[0] = -1

println(a.contentToString())
// Without the copy:
[-1, 2, 3]
which is not what we expect at all. And yes, in this example, the array is copied 2 times. This is why it's highly recommended that library authors always provide an overload that accepts a
List
or
Collection
, so users can pass through lists (without copy) instead of using the spread operator.
💯 1