Scala: override implicit parameter in constructor

I have a class that takes an implicit parameter that is used by functions called inside the class of methods. I want to be able to either override this implicit parameter, or, alternatively, the implicit argument will be copied from its source. As an example:

def someMethod()(implicit p: List[Int]) { // uses p } class A()(implicit x: List[Int]) { implicit val other = List(3) // doesn't compile def go() { // don't want to put implicit inside here since subclasses that override go() have to duplicate that someMethod() } } 

The behavior I want is that someMethod () gets an implicit parameter, which is some modified version of x, which was an implicit parameter of the class. I want to be able to either mutate x without changing it in order to pass it to constructor A, or otherwise override it with a new value of my choice. Both approaches do not seem to work. That is, it does not copy the list in the first case, and the compiler finds an ambiguous implicit value for the last case. Is there any way to do this?

I understand that I can override the implicit value in go (), but this is not a good choice in my case, because this class is subclassed many times, and I would like to handle this implicit change only in the base class, therefore, it is not necessary to go to the constructor , but it must be in a method other than go ().

+4
source share
3 answers

Introduce another type of wrapper, just to disambiguate:

 // badly named, choose something domain-specific case class ListHolder(theList: List[Int]) def someMethod()(implicit holder: ListHolder) { val xs = holder.theList // uses xs ... } class A()(implicit xs: List[Int]) { implicit val other = ListHolder(42 :: xs) // compiles def go() { // xs is never considered for the implicit param to someMethod() // because it now the wrong type } } 

It also makes the code more self-documenting, as it becomes dazzlingly obvious that the two implications are not the same thing.

+8
source

If you want the zillions levels floating around it to not collide with each other, you can create a wrapper class that you can mark with a marker for implicit use. There are many syntaxes you could use; here is one example:

 object Example { class Implication[A,B](val value: A) { def apply[C](c: C) = new Implication[C,B](c) } object Implication { def mark[B] = new Implication[Unit,B](()) implicit def implication_to_value[A,B](i: Implication[A,B]) = i.value } trait One {} trait Two {} implicit val x = Implication.mark[One]("Hello") implicit val y = Implication.mark[Two]("Hi") def testOne(implicit s: Implication[String,One]) = println(s: String) def testTwo(implicit s: Implication[String,Two]) = println(s: String) def testThree(s: String) = println("String is " + s) def main(args: Array[String]) { testOne testTwo testThree(x) testThree(y) } } 

Works the way you hope:

 scala> Example.main(Array()) Hello Hi String is Hello String is Hi 

Since you must use a wrapper object, it is not super-efficient, but can be very efficient. (Or very confusing, considering how implicit this is.)

+3
source

This modification is compiled. I changed x to var:

 class A()(implicit var x: List[Int]) { def someMethod()(implicit p: List[Int]) { // uses p } x = List(3) def go() { // don't want to put implicit inside here since subclasses that override go() have to duplicate that someMethod() } } 
0
source

All Articles