top of page
Writer's picturePranay Kundu

Fancy world of Implicits: Basics - Functional Programming with Scala - 101 Series

Updated: Jan 16, 2021

Implicits are one of the things that bless a developer with so much each of coding. As the name suggests, implicits are implicitly defined/mentioned elements of the code, which are referred automatically when something is missing in place.

scala implicits meme

We try to understand the most popular use-cases in this article. We will also explore the do's and don'ts while using implicits in various use cases. First, let's look into how implicits work briefly.


Working


Lexical scope


Just like compiler looks for the variables with the same name in the lexical scope(code block from where it can be referenced), implicit values are looked for the similar type.


Implicit scope


If implicit type is a class A type, then the compiler also looks in the scope of the companion object of class A, but class A is typed class, i.e. A[T] then the compiler will look into the companion object of A and if not found then in the companion object of B.


How to use?


Implicit val, var and def


Variables and methods can be declared implicit as and when required for effective design. Implicit resolutions happen the same way as we had discussed. Let's look at some of the examples:

implicit val i: Int = 6

// Implicit parameter should be the last in the list 
def printInt(name : String)(implicit j: Int) = { 
  println(s"$name has $j apples!")
}

printInt("Raj")

Here, we have defined an implicit val of type Int and same is expected by a def. So when you do a function call, you may or may not provide the argument, it will be resolved automatically.

Output: Raj has 6 apples!

If we had passed an argument to the implicit Int argument, the new value overrides the implicit value.

printInt("Raj")(7)

Output: Raj has 7 apples!

Allowed method of using implicits for parameters is very strict and each def can have only one implicit parameter list.

def func(implicit x: Int) // x is implicit
def func(implicit x: Int, y: Int) // x and y are implicit
def func(x: Int,implicit y: Int) // wont compile
def func(x: Int)(implicit y: Int) // only y is implicit
def func(implicit x: Int)(y: Int) // wont compile
def func(implicit x: Int)(implicit y: Int) // wont compile

Similarly, we can define an implicit method which gets called whenever required.

implicit def IntToStr(k: Int) = s"Int value is: $k"
def printMessage(str: String) =  str

println(printMessage(4))

the Int is converted to string implicitly on the go.

Output: Int value is: 4

Do's :

  • Implicit contexts are a popular use case where the evaluation context needs to be passed in all places, especially while dealing with futures.

  • Akka actor system heavily uses implicit contexts to pass on evaluation context for the thread pools maintained by the actor system.

Don'ts :

  • Don't define same type implicits in the same scope.

  • Don't overuse the implicit but use when design allows it.

  • Try to avoid the use of implicit type conversions -

// Implicit Type conversions

implicit def str2int(str: String): Int = Integer.parseInt(str)

def plusOne(add: Int): Int = add + 1

plusOne("foo") // Won't show error at compile time but will throw exception at runtime

Exception it throws:

Exception in thread "main" java.lang.NumberFormatException: For input string: "foo"

For advanced scala developers, there is a comprehensive discussion raised by the man himself, Martin Odersky on How implicit type conversions are evil and we won't need them in future.



Conclusion


In the next article, we will discuss the design patterns revolving around implicits. You can find the basic code here. Till then, Cya.

162 views0 comments

Comments


bottom of page