Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When does it make sense to use implicit parameters in Scala, and what may be alternative scala idioms to consider?

Tags:

scala

implicit

Having used a Scala library that liberally exposes the reliance on implicits to the caller, I had experienced friction around this mechanism, as Scala makes it quite hard at times to debug implicit arguments, and because there's quite a bunch of places Scala would fill in values for implicit arguments from. (I could almost relate to it as "implicits hell" at one time).

At one time in my coding, Scala "complained" an implicit value could not be matched whereas in fact there was a "collision" of implicit values each coming from a different import.

Regardless of that perceived brittleness, it may at times feel borderline to an abuse of the context design pattern.

Why does it make sense to have implicit parameters in Scala? In what scenarios would you use them and how would you avoid trouble?

As I'm not sure the experimentation-curve and potential for other team members getting totally confused are worth it, could you possibly suggest other scala idioms for sharing context between a multitude of Scala functions?

This questions is not for a specific implementation at hand, hopefully it's still a good fit for this site.

like image 913
matanster Avatar asked Aug 22 '14 18:08

matanster


People also ask

Why do we use implicit in Scala?

The implicit system in Scala allows the compiler to adjust code using a well-defined lookup mechanism. A programmer in Scala can leave out information that the compiler will attempt to infer at compile time. The Scala compiler can infer one of two situations: A method call or constructor with a missing parameter.

What is implicit argument in Scala?

Implicit parameters are the parameters that are passed to a function with implicit keyword in Scala, which means the values will be taken from the context in which they are called.

What is implicit method in Scala?

Scala implicit allows you to omit calling method or parameter directly. For example, you can write a function that converts int to/from string explicitly but you can ask the compiler to do the same thing for you, implicitly.

What are implicit parameters?

What Are Implicit Parameters? Implicit parameters are similar to regular method parameters, except they could be passed to a method silently without going through the regular parameters list. A method can define a list of implicit parameters, that is placed after the list of regular parameters.


1 Answers

Generally, using a common type as an implicit parameter is a bad idea.

def badIdea(n: Int)(implicit s: String) = s * n

It doesn't take much to imagine why: you'll get conflicting implicits for the same thing if anyone else adopts this policy. Better to avoid it.

But who really wants to manually stuff in a scala.concurrent.ExecutionContext manually every time it's needed (which is practically everywhere)?

So the key is: when you have something with a specialized type, especially if it's bookkeeping that might need to be overridden manually but mostly should just do the right thing, then use implicit parameters. (This usually covers type classes as well.)

Then what do you do if you really need a string? Well, wrap it (at least formally--here it's a value class so in some contexts it will just pass the string around):

class MyWrappedString(val underlying: String) extends AnyVal {}
implicit val myString = new MyWrappedString("bird")
def decentIdea(n: Int)(implicit mws: MyWrappedString) = mws.underlying * n

scala> decentIdea(2)  // In the bush?
res14: String = birdbird

Or if you think some additional logic is helpful, write a wrapper that takes an extra type parameter:

class ImplicitWithValue[K,V](val value: V) {
  // Any extra generic logic goes here
}
object ImplicitWithValue {
  class ValuePart[K] {
    def apply[V](v: V) = new ImplicitWithValue[K,V](v)
  }
  private val genericValuePart = new ValuePart[Any]
  private def typedValuePart[K] = genericValuePart.asInstanceOf[ValuePart[K]]
  def apply[K] = typedValuePart[K]
}

Then you can

trait Marker1
implicit val implicit1 = ImplicitWithValue[Marker1]("fish")

def goodIdea(n: Int)(implicit ms: ImplicitWithValue[Marker1, String]) = ms.value * n

scala> goodIdea(3)
res17: String = fishfishfish
like image 62
Rex Kerr Avatar answered Oct 02 '22 14:10

Rex Kerr