Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala: Overload (Seq[T]) and (T*)

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?

like image 798
Heinzi Avatar asked Sep 20 '12 12:09

Heinzi


2 Answers

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]

like image 131
Dylan Avatar answered Sep 21 '22 21:09

Dylan


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
like image 29
Rogach Avatar answered Sep 23 '22 21:09

Rogach