Jus12
Jus12

Reputation: 18024

Casting Array[Any] to Varargs in Scala

I have a method foo that takes Seq[Any]. For example:

def foo(a:Seq[Any]) = println(a.size)

foo(Seq("hi", 1, true)) // prints 3

I would have liked to avoid writing Seq every time. So I would like to define a method bar that I could call as:

bar("hi", 1, true) 

having the same effect as calling foo(Seq("hi", 1, true)).

Defining the following:

def bar(b:Any *) = foo(b)

and using it as:

bar("hi", 1, true) // prints 1

does not work as expected. It assigns b to the first element of the Seq passed to foo. Is there any way I can define bar so that it correctly invokes foo?

Upvotes: 0

Views: 414

Answers (2)

sarveshseri
sarveshseri

Reputation: 13985

You should not be having that problem, That code should work fine and is working fine for me.

scala> def foo(a:Seq[Any]) = println(a.size)
foo: (a: Seq[Any])Unit

scala> def bar( b: Any* ) = foo( b )
bar: (b: Any*)Unit

scala> bar( "hi" , 34, 23 )
3

scala> bar( "hi" , 34, true )
3

The reason this is happening is becasue *-paramters are implicitly received as Seq in function-body. Which means even if you pass multiple varargs paramters, these will be received as a Sequence inside your function.

You can again convert a Sequence of things to multiple varargs paramters using the _* annotation.

_* is the special annotation that is usable only in arguments to *-parameter of a function. It makes any sequence to be passed as a *-parameter.

Following examples will clear things.

scala> val l = List( 4, 5, 6, 7, 3, 6, 3 )
l: List[Int] = List(4, 5, 6, 7, 3, 6, 3)    

scala> def pp( ints: Int* ) = println( ints )
pp: (ints: Int*)Unit

// All Int* are implicitly received as a Seq[ Int ]
// Hence, ints will be a Seq[ Int ] in function body
// ( WrappedArray[ int ] in this case ) in function body.
scala> pp( 4, 5, 6 )
WrappedArray( 4, 5, 6 )

// Received as List[ Int ] in this case
scala> pp( l: _* )
List(4, 5, 6, 7, 3, 6, 3)

scala> def a( ints: Int* ) = ints.sum
a: (ints: Int*)Int

// passing a list wont work
scala> a( l )
<console>:11: error: type mismatch;
  found   : List[Int]
  required: Int
           a( l )
              ^

// list passed as multiple parameters
scala> a( l: _* )
res8: Int = 34

Upvotes: 1

Jus12
Jus12

Reputation: 18024

Found the answer. Defining bar as

def bar(b:Any *) = foo(b.toSeq)

does the trick.

Upvotes: 0

Related Questions