Scala: Passing one implicit parameter implicitly and the other explicitly. Is it possible?

StackOverflow https://stackoverflow.com/questions/22552985

  •  18-06-2023
  •  | 
  •  

Вопрос

Let's consider the function:

def foo(implicit a:Int, b:String) = println(a,b).

Now, let us assume that there is an implicit String and Int (implicit val i1=1) in scope but we want to pass an other, not implicit Int (val i2=2) explicitly to foo .

How can we do that ? Is it possible? Thanks for reading.

Это было полезно?

Решение

All I can add is:

def foo(implicit a: Int, b: String) = println(a, b)
implicit val i1 = 1
implicit val s = ""
val i2 = 2
foo(i2, implicitly[String])

Другие советы

In case your method has many implicit parameters (I sometimes have in my projects) and you sometimes want to just specify one of them explicit and let the others been resolved implicitly you can write implicitly for every other parameter like showed in my other answer. But sometimes you will change the signature of that method or the explicit parameter is in the middle of that parameter list, then you can make more readable client code with the following construct:

Suppose you have some types and their implicit dummy objects:

trait I1; implicit object I1 extends I1
trait I2; implicit object I2 extends I2
trait I3; implicit object I3 extends I3
trait I4; implicit object I4 extends I4
trait I5; implicit object I5 extends I5
trait I6; implicit object I6 extends I6

Now you have your method foo1 that uses these implicits:

def foo1(implicit i1: I1, i2: I2, i3: I3, i4: I4, i5: I5, i6: I6) {
  println(i1, i2, i3, i4, i5, i6)
}

Now you often want to explicitly specify i4: I4. So you write:

val i4 = new I4 {}
foo1(implicitly, implicitly, implicitly, i4, implicitly, implicitly)

Ugly!
With the following (should be placed in tight scope to method foo2 and perhaps renamed) wrapper for all implicits:

object Implicits {
  def apply(i4: I4)(implicit i1: I1, i2: I2, i3: I3, i5: I5, i6: I6) = new Implicits(i1, i2, i3, i4, i5, i6)
  implicit def applying(implicit i1: I1, i2: I2, i3: I3, i4: I4, i5: I5, i6: I6) = new Implicits(i1, i2, i3, i4, i5, i6)
}
class Implicits(val i1: I1, val i2: I2, val i3: I3, val i4: I4, val i5: I5, val i6: I6)

and the related method foo2:

def foo2(implicit implicits: Implicits) = {
  import implicits._
  println(i1, i2, i3, i4, i5, i6)
}

you can now call foo2 instead of foo1 the following way:

locally {
  foo2 // using implicit dummy objects I1, ..., I6 from above
  // or with explicit I4:
  val i4 = new I4 {}
  foo2(Implicits(i4))
}
  1. Explicitly call foo(i2, s1) but you loose the benefit of the use of the implicit String
  2. Define def foo1(a: Int)(implicit b: String)=foo(a,b) and you call foo1(i2)

You can create a new inner scope and define a new implicit val in it. The advantage is than when you have multiple function calls, this way you can override the one implicit for all of them in one place:

def foo(implicit a:Int, b:String) = println(a,b).

implicit val i = 1
implicit val s = ""

foo // call with original implicits

{
  implicit val i = 2

  foo // call with a new Int implicit

  foo // call with a new Int implicit again

}

Note: the new implicit must have the same variable name as the original one, so that it hides it, otherwise you will get a compiler error about ambiguous implicit values.

I know it's an old question but it still may be interesting. A nice way to do it is using implicitly as a default value:

scala> def foo(a: Int = implicitly[Int], b: String = implicitly[String]) = println(a,b)

scala> foo()
(10,boo)

scala> foo(50)
(50,boo)

scala> foo(b="bar")
(10,bar)
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top