3
votes

here's the basic example.. I can't get scala to recognize that I want the ability to initialize my class in 2 different ways: via an existing sequence, or using multiple parameters.

The error I receive is:

double definition: method apply:(params: Int*)chorle.scala.tests.MultiParam and method apply:(pList:
Seq[Int])chorle.scala.tests.MultiParam at line 9 have same type after erasure: (params: Seq)chorle.scala.tests.MultiParam

Which ok, I get what's going on here - post compilation both functions result in the same header signature. However, in practice they do not work the same way - I can't envoke : apply(1,2,3) if I only have the apply(Seq) version... and I can't envoke apply(seq) the other way around. I am aware of various ways I could patch the actual function call, but how do I address this properly and only once in the class? Thank you!

class MultiParam protected (pList:Seq[Int]) 

object MultiParam {
  def apply(pList:Seq[Int]): MultiParam = new MultiParam(pList)
  def apply(params: Int *): MultiParam = new MultiParam(params)


} 
2

2 Answers

5
votes

The problem comes from the fact that the so-called "repeated params" form is syntactic sugar, both at the definition site and the invocation site for a special kind of IndexedSeq, which leads to the ambiguity.

There's a stock way to handle this, which you can find at various places in the standard collections library:

package rrs.scribble

object MP {
  class MultiParam protected (pList:Seq[Int]) {
    override def toString: String = pList.mkString("[[", ", ", "]]")
  }

  object MultiParam {
    def apply(): MultiParam = new MP.MultiParam(List.empty[Int])
    def apply(ints: Seq[Int]): MultiParam = new MP.MultiParam(ints)
    def apply(i1: Int, iMore: Int*): MultiParam = new MP.MultiParam(i1 +: iMore)
  }
}

In the REPL:

scala> MultiParam()
res0: rrs.scribble.MP.MultiParam = [[]]

scala> MultiParam(12)
res3: rrs.scribble.MP.MultiParam = [[12]]

scala> MultiParam(12, 34)
res4: rrs.scribble.MP.MultiParam = [[12, 34]]

scala> MultiParam(12, 34, 56)
res5: rrs.scribble.MP.MultiParam = [[12, 34, 56]]
4
votes

Well, they can't be used as is because there's no way to generate both methods. The only way around it is to disambiguate them:

object MultiParam {
  def apply(pList:Seq[Int]): MultiParam = new MultiParam(pList)
  def apply(param: Int, params: Int *): MultiParam = new MultiParam(param +: params)
  def apply(): MultiParam = new MultiParam(Nil)
}