3

Is there a difference between a method parameter String* and Array[String]?

Console:

scala> def main(args: Array[String]): Unit = {}
main: (args: Array[String])Unit

scala> def main(args: String*): Unit = {}
main: (args: String*)Unit

Code 1:

object Example {
  def main(args: Array[String]): Unit = {
    println("Hello")
  }
}

>> Hello

Code 2:

object Example {
  def main(args: String*): Unit = {
    println("Hello")
  }
}

>> Exception in thread "main" java.lang.NoSuchMethodException: Example.main([Ljava.lang.String;)
    at java.lang.Class.getMethod(Class.java:1786)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:126)
puhlen
  • 8,400
  • 1
  • 16
  • 31
rapt
  • 11,810
  • 35
  • 103
  • 145
  • 1
    Possible duplicate of [How to pass scala Array into scala vararg method?](https://stackoverflow.com/questions/31064753/how-to-pass-scala-array-into-scala-vararg-method) – prayagupa Aug 30 '17 at 23:40

2 Answers2

7

Yes,

String* is a varargs, it takes in any number of Strings, which will be passed to the method as a Seq[String].

Array[String] take in a single Array of Strings.

If you have a sequence of String that you want to pass as a String*, you cannot do so directly, but you can "splat" out the sequence to pass it in using the :_* type ascription.

def varArg(input: String*){}

val strings = Seq("hello", "world")
varArg(strings:_*)
puhlen
  • 8,400
  • 1
  • 16
  • 31
  • So is `String*` a type or just how varargs is expressed in the console? How can I see in the console that it's passed to the method as Seq[String]? P.S. This old answer says it is passed as Array, did it change at some point to Seq? https://stackoverflow.com/a/1438796 – rapt Aug 30 '17 at 23:33
  • @rapt I *think* it is a type but I'm not sure. It is only usable as a method parameter either way. The more upvoted and detailed answer form that question also mentions that it is a Seq. You can also find out for yourslef in the repel by defining a varargs method and seeing what you get. `def test(args: String*) = args`. We see that it returns a `Seq[String]`, the actual implementation depends though, when we pass in arguments the concrete implementation is `WrappedArray` but if we pass no arguments it is `Nil` (the empty List aka. `List()`) – puhlen Aug 31 '17 at 00:52
  • I downvoted the linked answer for that error; Java uses arrays, Scala uses Seq. The repeated param has a type that is a Seq, http://scala-lang.org/files/archive/spec/2.12/04-basic-declarations-and-definitions.html#repeated-parameters. The vararg itself is a type internal to the compiler, but we don't normally see that. – som-snytt Aug 31 '17 at 01:15
  • It would be cool if you could get the compiler to make a bridge to a varargs main, I don't know why they don't do that. Worth adding that this is what App is for. – som-snytt Aug 31 '17 at 01:19
2

I went and asked on the forum.

The annotation you want is annotation.varargs.

I had some inkling that they had that glue, but I never had a reason to use it.

Personally, I'd rather it were automatic for a main method, b/c obvious.

$ scala
Welcome to Scala 2.12.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_131).
Type in expressions for evaluation. Or try :help.

scala> object Main { @annotation.varargs def main(args: String*) =
     | println(args.size)
     | }
defined object Main

scala> Main.main(Array("hello","world"): _*)
2

OK, cool.

som-snytt
  • 39,429
  • 2
  • 47
  • 129