1

this is my situation:

trait BPO
trait BBO
class PointBO extends BBO
class PointPO extends BPO
class CircleBO extends BBO
class CirclePO extends BPO

trait Mapper[-P <: BPO,+B <: BBO] {
  def mapAsBBO(bpo: P): B
}

class PointMapper extends Mapper[PointPO,PointBO]{
  override def mapAsBBO(bpo: PointPO): PointBO = {
    println("Construct point")
    new PointBO
  }
}

class CircleMapper extends Mapper[CirclePO,CircleBO] {
  override def mapAsBBO(bpo: CirclePO): CircleBO = {
    println("Construct circle")
    new CircleBO
  }
}

class Registry{
  def method[P,B](po:P,bo:B)(implicit mapper: Mapper[P,B]) = mapper.mapAsBBO(po)
}

val r = new Registry
val s = r.method[PointPO,PointBO](new PointPO,new PointBO)

I would like to pass to the method method, just both classes involved in the mapping and let Scala type inference to implement for me the right mapper, is it possible?

I'm receiving this error:

Error:(31, 40) could not find implicit value for parameter mapper: A$A191.this.Mapper[A$A191.this.PointPO,A$A191.this.PointBO] lazy val s = r.method[PointPO,PointBO](new PointPO,new PointBO) ^

Another way should be fine for me, would be called the method method passing it just the mapper class:

val s = r.method[PointMapper](new PointPO,new PointBO)

Is this any way to accomplish one of this street and if one of them is better that the other, plus a little explanation.

EDIT:

In origin I would like to make trait Mapper with both parameters covariant:

trait Mapper[+P <: BPO,+B <: BBO] {
  def mapAsBBO(bpo: P): B
}

like that would be fine the assignment below:

val d:Mapper[BPO,BBO] = new CircleMapper()

but the compiler complain me about P parameter that must be controvariant

There is an alternative solution to do that?

Regards.

Giorgio
  • 1,073
  • 3
  • 15
  • 33
  • For your second question regarding covariance, have a look here: https://stackoverflow.com/questions/9619121/why-is-parameter-in-contravariant-position – thwiegan Jun 07 '17 at 13:28

1 Answers1

1

Well first of all, in your code the implicit mapper is missing ( as mentioned in the exception ).

So I added these below. Aside from that if you add the implicit values for your mappers, you have a type boundary issue, as the method needs the same type boundaries as your Mapper, so I also adapted this:

trait BPO
trait BBO
class PointBO extends BBO
class PointPO extends BPO
class CircleBO extends BBO
class CirclePO extends BPO

trait Mapper[P <: BPO,B <: BBO] {
  def mapAsBBO(bpo: P): B
}

class PointMapper extends Mapper[PointPO,PointBO]{
  override def mapAsBBO(bpo: PointPO): PointBO = {
    println("Construct point")
    new PointBO
  }
}

class CircleMapper extends Mapper[CirclePO,CircleBO] {
  override def mapAsBBO(bpo: CirclePO): CircleBO = {
    println("Construct circle")
    new CircleBO
  }
}

class Registry{
  def method[P <: BPO,B <: BBO](po:P,bo:B)(implicit mapper: Mapper[P,B]) = mapper.mapAsBBO(po)
}

implicit val pMapper = new PointMapper()
implicit val cMapper = new CircleMapper()

val r = new Registry
r.method(new PointPO,new PointBO)

EDIT

Removed explicit type parameters from r.method because they are inferred by the compiler. Also removed co- and contra-variance from the Mapper type parameters, since for this functionality it is not needed and no further context is given as to why it is being used, so it would only lead to confusion.

EDIT2

In case you have no reason to instantiate the mapper classes you could also define them as implicit objects:

trait BPO
trait BBO
class PointBO extends BBO
class PointPO extends BPO
class CircleBO extends BBO
class CirclePO extends BPO

trait Mapper[P <: BPO,B <: BBO] {
  def mapAsBBO(bpo: P): B
}

implicit object PointMapper extends Mapper[PointPO,PointBO]{
  override def mapAsBBO(bpo: PointPO): PointBO = {
    println("Construct point")
    new PointBO
  }
}

implicit object CircleMapper extends Mapper[CirclePO,CircleBO] {
  override def mapAsBBO(bpo: CirclePO): CircleBO = {
    println("Construct circle")
    new CircleBO
  }
}

class Registry{
  def method[P <: BPO,B <: BBO](po:P,bo:B)(implicit mapper: Mapper[P,B]) = mapper.mapAsBBO(po)
}

val r = new Registry
r.method(new PointPO,new PointBO)
thwiegan
  • 2,163
  • 10
  • 18