Search code examples
scalaimplicitscontext-bound

Scala: How to get context bound List[T] conversion working here?


This is my first question here so hope I provide enough detail. Feel free to ask for clarification.

Taking the following into consideration, which works:

implicit def optionBsonReader[T, U](implicit ev: BsonReader[T, U]) = new BsonReader[Option[T], Option[U]] {
  def read(obj: Option[U]): Option[T] = {
    obj match {
      case Some(x) => Some(x.fromBson[T])
      case None => None
    }
  }
}

This piece of code converts Option wrapped pieces of BSON to another Option[T]. I thought that the same would work for lists but the following doesn't compile:

implicit def listBsonReader[T, DBObject](implicit ev: BsonReader[T, DBObject]) = new BsonReader[List[T], MongoCursor] {
  def read(cur: MongoCursor): List[T] = {
    cur.map(_.fromBson[T]).toList
  }
}

I am using the following code for the general mechanics:

package object bson {

  def bsonReader[A, B](implicit reader: BsonReader[A, B]) = reader
  def bsonWriter[A, B](implicit writer: BsonWriter[A, B]) = writer

  implicit def addWriter[A](any: A): WithWriter[A] = new WithWriter(any)
  implicit def addReader[A](any: A): WithReader[A] = new WithReader(any)
}

package bson {
  private[bson] class WithWriter[A](any: A) {
    def toBson[B](implicit writer: BsonWriter[A, B]): B = writer.write(any)
  }
  private [bson] class WithReader[B](any: B) {
    def fromBson[A](implicit reader: BsonReader[A, B]): A = reader.read(any)
  }
}

Compiler error: could not find implicit value for parameter reader: project.marshalling.bson.BsonReader[T,com.mongodb.casbah.Imports.DBObject] cur.map(_.fromBson[T]).toList

This strikes me as odd since it seems like the compiler is trying to evaluate T before fromBson has been called to supply a type. This strikes me as especially odd since the option reader seems to have no such complaints. I've only recently started to code in Scala in earnest so I am sure I am missing something here.

Please let me know if you need more info and hope you can help.

Best,

Dirk


Solution

  • In your listBsonReader, there is no reason for type U. Your cursor iterate on DBObject, map expects a DbObject => X function. I guess you have something like

    implicit def withFromBson[U](x: U) = new {
       def fromBson[T](implicit ev : BsonReader[T,U]) : T = ...
    }
    

    In map, with _ typed DBObject, it is, quite normally looking from BsonReader[T, DBObject]. You provide none in implicit scope, only a BsonReader[T,U]. Just remove U and have your implicit parameter be BsonReader[T,DBObject].

    The compiler is not trying to evaluate T in advance. It is trying to ensure that whatever T and U may be at call site, (in this case, U is the problem), it will have the implicit BSonReader[T, DBObject] it needs in implicit scope. I guess there is none in the general environment. You promise, with your implicit parameter, that you will give one BsonReader[T,U] at call site. That is not what it needs. Where the parameter not implicit (you would have to write the ev at when calling fromBson), you would have a similar error.