1

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.

4
  • You move the things that need the implicits to a lower scope, inside the LengthProvider implementation. Instead of having them as constructor arguments, you do a per method approach. Commented Apr 12, 2016 at 15:30
  • Well, this helped. Feel free to post it as an answer, I'll accept it. Commented Apr 12, 2016 at 15:43
  • Possible duplicate of scala typing require implicit Commented Apr 12, 2016 at 15:56
  • The underlying codebase is the same indeed, but the questions are different, and the solutions proposed are different. Commented Apr 12, 2016 at 17:56

2 Answers 2

2

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
}
Sign up to request clarification or add additional context in comments.

Comments

0

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 was Transaction => 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 to scala.Function1[A, B], the implicit function type syntax implicit A => B desugars to scala.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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.