26

In Python, we have the star (or "*" or "unpack") operator, that allows us to unpack a list for convenient use in passing positional arguments. For example:

range(3, 6)
args = [3, 6]
# invokes range(3, 6)
range(*args)

In this particular example, it doesn't save much typing, since range only takes two arguments. But you can imagine that if there were more arguments to range, or if args was read from an input source, returned from another function, etc. then this could come in handy.

In Scala, I haven't been able to find an equivalent. Consider the following commands run in a Scala interactive session:

case class ThreeValues(one: String, two: String, three: String)

//works fine
val x = ThreeValues("1","2","3")

val argList = List("one","two","three")

//also works
val y = ThreeValues(argList(0), argList(1), argList(2))

//doesn't work, obviously
val z = ThreeValues(*argList)

Is there a more concise way to do this besides the method used in val y?

Jeff Evans
  • 1,257
  • 1
  • 15
  • 31
  • 8
    Mistakenly marked as duplicate, whereas it is not. Scala has `:_*` operatoration, but it only works with varargs on the definition side: e.g. `case class Things(xs: String*)` – om-nom-nom Feb 22 '13 at 23:01

4 Answers4

41

There is no direct equivalent in scala. The closest thing you will find is the usage of _*, which works on vararg methods only. By example, here is an example of a vararg method:

def hello( names: String*) {
  println( "Hello " + names.mkString(" and " ) )
}

which can be used with any number of arguments:

scala> hello()
Hello
scala> hello("elwood")
Hello elwood
scala> hello("elwood", "jake")
Hello elwood and jake

Now, if you have a list of strings and want to pass them to this method, the way to unpack it is through _*:

scala> val names = List("john", "paul", "george", "ringo")
names: List[String] = List(john, paul, george, ringo)
scala> hello( names: _* )
Hello john and paul and george and ringo    
Régis Jean-Gilles
  • 32,541
  • 5
  • 83
  • 97
5

You can get some way towards the Python using shapeless,

Welcome to Scala version 2.11.0-20130208-073607-ce32c1af46 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_05).
Type in expressions to have them evaluated.
Type :help for more information.

scala> import shapeless._
import shapeless._

scala> import Traversables._
import Traversables._

scala> case class ThreeValues(one: String, two: String, three: String)
defined class ThreeValues

scala> val argList = List("one","two","three")
argList: List[String] = List(one, two, three)

scala> argList.toHList[String :: String :: String :: HNil].map(_.tupled).map(ThreeValues.tupled)
res0: Option[ThreeValues] = Some(ThreeValues(one,two,three))

As you can see, a little more ceremony is required in Scala with shapeless. This is because shapeless imposes compile time constraints which are guaranteed to be satisfied at runtime (unlike the python, which will fail at runtime if args is the wrong size or contains elements of the wrong type) ... instead you're forced to specify the type you expect the List to have (in this case exactly three Strings) and be prepared to handle the case where that expectation isn't satisfied (because the result is explicitly an Option of ThreeValues).

Miles Sabin
  • 23,015
  • 6
  • 61
  • 95
  • Thank you for this. I recently attended a talk on Shapeless, and this answer (now more than five years old), finally really resonates. – Jeff Evans May 22 '19 at 17:52
4

There is something similar for functiones: tupled It converts a function that takes n parameters into a function that takes one argument of type n-tuple.

See this question for more information: scala tuple unpacking

Such a method for arrays wouldn't make much sense, because it would only work with functions with multiple arguments of same type.

Community
  • 1
  • 1
Jens Schauder
  • 77,657
  • 34
  • 181
  • 348
  • Agreed that it wouldn't make sense given all the args would have to be the same type. In the particular use case I'm considering, `argList` will actually come from splitting a string provided as input, and I would `implicit def` some conversions to turn Strings into those various types required by the function I'm trying to call. But even then, I would have to build a Tuple from a List, I suppose. – Jeff Evans Feb 22 '13 at 23:14
  • 1
    Somebody build an HList, which is basically a list with a independent type for each element. Might be able to convert this to a tuple ... Just an idea. – Jens Schauder Feb 22 '13 at 23:25
  • 1
    @JensSchauder An idea which happens to be implemented by both Scalaz and Shapeless, though Shapeless takes it much further. – Daniel C. Sobral Feb 23 '13 at 00:13
2

Another way of unpacking a list:

val a :: b :: c :: _ = argList
val z = ThreeValues(a, b, c)
UnitasBrooks
  • 1,062
  • 7
  • 15