5
votes

I have a case class, taking a Seq[T] as parameter:

case class MyClass(value: Seq[T])

I now want to be able to write

MyClass(t1,t2,t3)

So I defined

object MyClass {
    def apply(value: T*) = new MyClass(value.toSeq)
}

It doesn't work, because the case class defines

object MyClass {
    def apply(value: Seq[T])
}

and Seq[T] and T* have the same type after erasure, so I can't overload them.

But I'd like to allow both access ways. Both ways should be allowed:

MyClass(t1,t2,t3)
MyClass(some_seq_of_T)

Since Seq[T] and T* are almost the same type (at least after erasure; and inside of the function having the parameter T* becomes Seq[T]), I think there should be a way to allow both ways of calling it.

Is there?

3
Is T some concrete type or your MyClass has a type parameter?Rogach

3 Answers

6
votes

You could cheat a little bit and define your companion like this:

case class MyClass[T](value: Seq[T])

object MyClass {
  def apply[T](first: T, theRest: T*) = new MyClass(first :: theRest.toList)
  def apply[T]() = new MyClass[T](Nil)
}

The first apply handles the MyClass(1,2,3) as long as there is at least one argument. The scond apply handles the 0-argument case. They don't conflict with the regular constructor.

This way you can write MyClass(Seq(1,2,3)), MyClass(1,2,3), and MyClass(). Just note that for the empty one you'll have to tell it what type to return, or else it will assume a MyClass[Nothing]

3
votes

Here is solution without case classes:

scala> class A[T] (ts: Seq[T]) { def this(ts: T*)(implicit m: Manifest[T]) = this(ts) }
defined class A

scala> new A(1)
res0: A[Int] = A@2ce62a39

scala> new A(Seq(1))
res1: A[Seq[Int]] = A@68634baf
0
votes

There can't be two methods of the same name where one takes a parameter of type Seq[T] and one takes T*. How would the compiler know whether a call like

val s = Seq(1,2,3) 
foo(s)

is supposed to call the first method or the second method (with T = Int) or the second one (with T = Seq[Int]) ?