Reputation: 6093
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?
Upvotes: 5
Views: 496
Reputation: 13922
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]
Upvotes: 6
Reputation: 27220
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
Upvotes: 3
Reputation: 42047
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]) ?
Upvotes: 0