tags:

views:

152

answers:

2

I'm quite new to Scala and struggling with the following:

I have database objects (type of BaseDoc) and value objects (type of BaseVO). Now there are multiple convert methods (all called 'convert') that take an instance of an object and convert it to the other type accordingly - like this:

def convert(doc: ClickDoc): ClickVO = ...
def convert(doc: PointDoc): PointVO = ...
def convert(doc: WindowDoc): WindowVO = ...

Now I sometimes need to convert a list of objects. How would I do this - I tried:

def convert[D <: BaseDoc, V <: BaseVO](docs: List[D]):List[V] = docs match {
    case List() => List()
    case xs => xs.map(doc => convert(doc))
}

Which results in 'overloaded method value convert with alternatives ...'. I tried to add manifest information to it, but couldn't make it work.

I couldn't even create one method for each because it'd say that they have the same parameter type after type erasure (List).

Ideas welcome!

+3  A: 

You need to do type-casting:

  //case class MyBaseDoc(x: Int, y: Int)
  //case class BaseVO(x: Int, y: Int)
  //case class ClickDoc(x: Int, y: Int) extends MyBaseDoc(x, y)
  //case class ClickVO(var x: Int, var y: Int) extends BaseVO(x, y)

  def convert(doc: ClickDoc): ClickVO  = doc match {
    case null => null
    case _ =>
      val result = new ClickVO
      result.x = doc.x
      result.y = doc.y
      result
  }


  def convert(docs: List[MyBaseDoc]):List[BaseVO] = docs match {
    case List() => List()
    case xs => xs.map(doc => convert(doc.asInstanceOf[ClickDoc]))
  }
Vasil Remeniuk
Thanks for your suggestion - but actually the problem is somewhere else. You see, I have _multiple_ convert methods (see UPDATED description above) - and when I write a generic convert method for lists, Scala cannot find the appropriate one.
stephanos
I'm afraid, you'll have to do an explicit pattern matching for that :(Implicit type-casting won't help solving this problem.
Vasil Remeniuk
+5  A: 

Don't think you need the generic parameters on the method. List is already covariant in Scala. You also don't need the pattern match - map will transform an empty list to itself. How about something like this:

def convert(docs: List[BaseDoc]):List[BaseVO] = docs map {
    case doc: ClickDoc => convert(doc)
    case doc: PointDoc => convert(doc)
    case doc: WindowDoc => convert(doc)
}

The other option is to move the convert methods to the various BaseDoc subclasses and allow it to be called polymorphically.

Ben Lings
Thanks for the detailed explanation!
stephanos