I was going through an older Kotlin tutorial, and ...
# announcements
c
I was going through an older Kotlin tutorial, and noticed some nice upgrades to the language. However, there is one place that seems so strange. This deals with varargs, arrays, spread operator, and named parameters.
Copy code
fun sayHello(greeting: String, vararg names: String) {
    names.forEach { name ->
        println("$greeting $name")
    }
}

fun main() {
    val interestingThings3 = arrayOf("Kotlin", "Programming", "Coding")
    sayHello(greeting = "Hi", *interestingThings3)
    sayHello(greeting = "Hi", names = *interestingThings3)
}
This works, but the last statement suggests to remove
Redundant spread (*) operator
. That leads to the following valid code.
Copy code
fun main() {
    val interestingThings3 = arrayOf("Kotlin", "Programming", "Coding")
    sayHello(greeting = "Hi", *interestingThings3)
    sayHello(greeting = "Hi", names = interestingThings3)
}
Since the last statement doesn't need the spread operator, I thought I would remove it from both
Copy code
fun main() {
    val interestingThings3 = arrayOf("Kotlin", "Programming", "Coding")
    sayHello(greeting = "Hi", interestingThings3)  // ERROR
    sayHello(greeting = "Hi", names = interestingThings3)
}
But this gives an error on the first statement. Why? Why does the first one error out, but the last one if perfectly fine.
n
in the second statement, you use named parameters in the first, you mix positional and named parameters i infer the compiler is confused with the mapping between varargs and array using positional params notice that the behavior is consistant in both cases if you use a positional parameter for
"Hi"
it’s just gut feeling a kotlin-expert would explain it i can only assume
c
I don't know if this is working as intended, but it just looked really weird. Basically
interestingThings3
is seen as a single parameter. Because of that, it needs to be a
String
but it is an
Array<String>
. That is why we need the spread operator to split the array into individual `String`s that can be passed in. That makes perfect sense by itself! However, it seems like when we use named parameters, the Kotlin Compiler treats
names
as a "collection" that can be automatically transformed into `String`s that can be passed into the vararg. Again, this makes perfect sense by itself. The issue is that these 2 methods take to very different approaches that shouldn't be mixed together (my view). To me, it seems like if the Kotlin compiler can figure it out without the spread operator for the named parameters, then it should be able to do that without named parameters
k
In Kotlin
Array<String>
is not assignable to
String...
like you would expect it from Java. Instead Kotlin requires you to do this conversion explicitly using the spread operator. This gives Kotlin the advantage of mixing arrays with additional arguments, like so
sayHello(greeting = "Hi", "Java", "can't", *interestingThings3, "do", "this")
. But this means you cannot pass an array to the function directly. So why does the second example work? If a
vararg
is passed using a named argument instead of a positional argument, then the excepted type is no longer
String...
but
Array<String>
. Kotlin does automatically convert
String...
to
Array<String>
, so the spread operator used in the second call becomes redundant. Basically its converting
Array<String>
to
String...
and then immediately back to
Array<String>
.
👍 1
👨‍🏫 1
The discrepancy between positional and named arguments it due to the fact, that arguments cannot span across multiple commas when written as named arguments. This means that
String...
has to become
Array<String>
in order to be passable as a single argument. So it’s not possible to write something like this
sayHello(greeting = "Hi", names = "Java", "can't", *interestingThings3, "do", "this")
. Instead you have to write something like this ``sayHello(greeting = "Hi", names = arrayOf("Java", "can't", *interestingThings3, "do", "this"))`.
👍 1
c
That counter example really helped a lot
k
Jlj lj.jljmlmmjlmjbjjjl.limlmp.jbmm.jln.llhljbl.
Jlj lljpj.jljjlj jmjmjulmiljjljmmbl..mhmjl.ljlljjpjjml.ljlpjlljb