Is there a way to implicitly convert an implicit parameter in Scala?
Is there a way to make this work (Scala 2.8.1):
class A
class B
def f(implicit b: B) {}
implicit val a = new A
implicit def aToB(a: A) = new B
f(a) // works ok
f // error: could not find implicit value for parameter b: B
Actually my problem is with Lift's (2.2) dependency injection, i'm trying to convert Vendor[T] to T and implicitly require it in a class constructor without adding imports after each val:
object DependencyFactory extends Factory {
implicit def vendorT开发者_运维技巧oVal[T](vendor: Vendor[T]): T = vendor.vend
implicit val db = new FactoryMaker[DbAccess](Model) {}
//uncommenting the following line makes it work, but can we avoid it?
//import db._
implicit val userStore = new FactoryMaker[UserStore](new UserStore) {}
}
Where UserStore
is:
class UserStore(implicit db: DbAccess)
Am i doing something wrong?
UPDATE
Thanks to Easy Angel for answering the first part. But it doesn't solve my Lift DI problem because it turns out that there is an opposite conversion in scope (from T to Vendor[T]) and having those both leads to 'error: diverging implicit expansion'.
Can it be solved?
UPDATE2
Wow one more problem after previous: having a conversion from some Container[T] to T with implicit instance of Container[U] in scope and a function with implicit parameter U leads to 'diverging implicit expansion' too:
class A
case class Vendor[T](v: T)
def f(implicit a: A) {}
implicit val vendor = Vendor(new A)
implicit def vendorToVal[T](implicit v: Vendor[T]) = v.v
f
Any hints?
You almost made it. You only need to declare a
implicit:
implicit def aToB(implicit a: A) = new B
In this case compiler tries to find some implicit B
for the first implicit argument of f
and it finds aToB
. Than compiler ties to satisfy aToB
's requirement (implicit a: A
) and finds your implicit val a
.
This is probably not the best and most concise solution to this problem. But it was interesting for me whether it's technically possible to achieve what you want. I tried to reproduce all involved classes as close as possible without Lift... and here is one of the possible solutions using view bounds:
class DbAccess
class UserStore[T](implicit db: T, ev: T => DbAccess)
class Vendor[T] (val vend: T)
class FactoryMaker[T] (vend: T) extends Vendor[T](vend)
implicit def vendorToVal[T](vendor: Vendor[T]) = vendor.vend
implicit val db: Vendor[DbAccess] = new FactoryMaker[DbAccess](new DbAccess) {}
implicit val userStore = new FactoryMaker[UserStore[Vendor[DbAccess]]](new UserStore) {}
In this case UserStore
knows fact, that T
is not DbAccess
, but it also knows that T
can be viewed and used as T
.
Edit
About your second example (in comment). This simple workaround comes to my mind:
class A
class B
trait HighPrio
def f(implicit b: B) {}
implicit val a = new A with HighPrio
implicit def aToB(implicit a: A with HighPrio) = new B;
implicit def bToA(implicit b: B) = new A;
f
... not sure whether it will work in your Lift case.
精彩评论