scalaplayframeworkplayframework-2.0scala-implicits

scala implicit in function type definition


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.


Solution

  • 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
    }