Wednesday, November 25, 2009

Varargs

Both Java and Scala have varargs. In Scala the syntax for a varargs argument is def method (param:String*). In the off-chance you are not aware of what varargs are; they allow an arbitrary number of values to be passed to the method. Some restrictions on when varargs can be used are:
  • The vararg parameter must be the last parameter in the list
  • There can not be default values for any parameters in the method containing the varargs (Scala 2.8+)

From the caller's point of view; varargs can be called as follows: method("p1""p2""p3") where the number of values is not limited. However, the () must be used.

In Java (if I remember right) only arrays can be passed in place of varargs:
  1. class C {
  2.   public static void main(String... args) {
  3.     System.out.println(args.length)
  4.   }
  5. }
  6. String[] args = new String[]{"arg1""arg2"}
  7. C.main (args)

However Scala is more general and allows any sequence to be passed to varargs, with a caveat. When a sequence is passed to varargs a hint must be provided to indicate that you are intending to have the sequence be expanded to be the varargs.
  1. def method (args:Int*) = println(args)
  2. val list = List(1,2,3)
  3. method (list:_*)  // note the use of _*

Examples:
  1. scala> def method(varargs:Int*)(more:String*) = println(varargs,more)
  2. method: (Int*)(String*)Unit
  3. scala> method(1,2,3,4)("one")
  4. (Array(1, 2, 3, 4),Array(one))
  5. scala> method(1,2,3,4)       
  6. < console>:6: error: missing arguments for method method in object $iw;
  7. follow this method with '_' if you want to treat it as a partially applied function
  8.        method(1,2,3,4)
  9.        ^
  10. scala> method(1,2,3,4)()
  11. (Array(1, 2, 3, 4),Array())
  12. scala> method()("one")  
  13. (Array(),Array(one))
  14. scala> method("one")  
  15. < console>:6: error: type mismatch;
  16.  found   : java.lang.String("one")
  17.  required: Int
  18.        method("one")
  19.               ^
  20. scala> method()()     
  21. (Array(),Array())
  22. scala> val method2 = method(1,2,3)_  
  23. method2: (String*) => Unit = < function>
  24. scala> val paramList = List("hi","ho")
  25. paramList: List[java.lang.String] = List(hi, ho)
  26. scala> method2(paramList)
  27. < console>:8: error: type mismatch;
  28.  found   : List[java.lang.String]
  29.  required: String
  30.        method2(paramList)
  31.                ^
  32. scala> method2(paramList:_*)
  33. (Array(1, 2, 3),List(hi, ho))
  34. scala> val range = (1 to 5) map {_.toString} 
  35. range: RandomAccessSeq.Projection[java.lang.String] = RangeM(1, 2, 3, 4, 5)
  36. scala> method2(range:_*)                     
  37. (Array(1, 2, 3),RangeM(1, 2, 3, 4, 5))

3 comments:

  1. Thanks, guy!

    It was helpful! ^^

    ReplyDelete
  2. Excellent Post, this was extremely helpful!

    ReplyDelete
  3. Thanks, your article helped me to understand varargs. I get some opposite results using Scala 2.10.3

    scala> def method(varargs:Int*)(more:String*) = println(varargs,more)
    method: (varargs: Int*)(more: String*)Unit
    scala> val method2 = method(1,2,3)_
    method2: Seq[String] => Unit =

    scala> method2(paramList)
    (WrappedArray(1, 2, 3),List(hi, ho))

    scala> method2(paramList:_*)
    :11: error: type mismatch;
    found : List[String]
    required: Seq[Seq[String]]
    method2(paramList:_*)
    ^

    scala> method2(range)
    (WrappedArray(1, 2, 3),Vector(1, 2, 3, 4, 5))

    scala> method2(range:_*)
    :11: error: type mismatch;
    found : scala.collection.immutable.IndexedSeq[String]
    required: Seq[Seq[String]]
    method2(range:_*)
    ^

    Do you mind shedding some lights?

    ReplyDelete