Reputation: 2796
I have following abstract class:
abstract class FieldProvider[+T: Writes](db: DB)(implicit i: RequestAction, j: ExecutionContext) {}
and following implementations:
class LengthProvider extends FieldProvider ...
object LengthProvider extends ((DB) => LengthProvider) {
def apply(v1: DB): LengthProvider = new LengthProvider(v1)
}
class WidthProvider extends FieldProvider ...
object WidthProvider extends ((DB) => WidthProvider) {
def apply(v1: DB): WidthProvider = new WidthProvider(v1)
}
The reason why I have these apply
methods is because I need following configuration map:
val providers: Map[String, ((DB) => FieldProvider)] = Map(
"length" -> LengthProvider,
"width" -> WidthProvider
)
So that I can initialize the providers by the string containing their name:
providers("length")(db) // returns a new instance of LengthProvider
Now, my problem is that all these providers constructors require two implicit variables. But I don't know how to include it into the function definition (DB) => FieldProvider
. So, essentially, the apply
method signature should be something like (DB)(implicit RequestAction, ExecutionContext) => FieldProvider
, but I don't know if there is a correct syntax for what I'm trying to do.
I could also give up and pass them explicitly:
object WidthProvider extends ((DB, RequestAction, ExecutionContext) => WidthProvider) {
def apply(v1: DB, v2: RequestAction, v3: ExecutionContext): WidthProvider = new WidthProvider(v1)(v2,v3)
}
But then I'll have to pass them explicitly elsewhere, instead of providers("length")(db)
, I'd have to write providers("length")(db, implicitly[RequestAction], implicitly[ExecutionContext])
, which doesn't feel right.
Upvotes: 1
Views: 310
Reputation: 1323005
So, essentially, the
apply
method signature should be something like(DB)(implicit RequestAction, ExecutionContext) => FieldProvider
, but I don't know if there is a correct syntax for what I'm trying to do.
Note that you might directly get (in a future Scala 2017 version) an implicit function type.
See pull request 1775, by Odersky himself.
Let’s massage the definition of
f1
a bit by moving the last parameter section to the right of the equals sign:
def f1(x: Int) = { implicit thisTransaction: Transaction =>
thisTransaction.println(s"first step: $x")
f2(x + 1)
}
The right hand side of this new version of f1 is now an implicit function value.
What’s the type of this value?
Previously, it wasTransaction => Int
, that is, the knowledge that the function has an implicit parameter got lost in the type.The main extension implemented by the pull request is to introduce implicit function types that mirror the implicit function values which we have already.
Concretely, the new type of f1 is:
implicit Transaction => Int
Just like the normal function type syntax
A => B
, desugars toscala.Function1[A, B]
, the implicit function type syntaximplicit A => B
desugars toscala.ImplicitFunction1[A, B]
.
The same holds at other function arities. With dotty’s pull request #1758 merged, there is no longer an upper limit of 22 for such functions.
Upvotes: 0
Reputation: 28511
Let's assume FieldProvider
has 2 methods that need the implicits. The more convenient way to avoid duplication is to pass them as constructor level implicit arguments and then all the internal methods in FieldProvider
can "share" them.
However, this won't help in your current class tree, so to fix this, instead of doing:
abstract class FieldProvider()(implicit param1: X1..) {
def test: T = param1.doSomething
}
Simply move the implicit to method level such that you can provide it at a time different than extending the constructor.
abstract class FieldProvider() {
def test()(implicit param1: X1): T = param1.doSomething
}
Upvotes: 2