Scala Implicits - Journey Begins

This article covers the 2 basic concepts of Scala Implicits. Implicit parameters and implicit conversions

Before you read

I am assuming that you know basic Scala Programming, Scala Type Bounds (aka Generics)

Implicit definition

Here what Scala docs say

Implicits in Scala refers to either a value that can be passed “automatically”, so to speak, or a conversion from one type to another that is made automatically. That's what Scala exactly does. Scala Docs

Scala has

  • implicit parameters
  • implicit conversions

The context in which they are used are entirely different. Lets explore each of them in detail

Implicit parameters

Firstly, the implicit parameters Lets start with a simple example. A method that calculates the area of a circle

 def areaOfCircle(radius: Double, piValue: Double): Double 
= piValue * radius * radius

println(areaOfCircle(5, 3.14))

Let us take another method that calculates the circumference of a circle

def circumferenceOfCircle(radius: Double, piValue: Double): Double 
= 2 * piValue * radius

println(circumferenceOfCircle(5, 3.14))

In the above two code snippets you can see that I must pass the radius and the value of pi. Let us send pi Value as an implicit variable. We slightly change the above methods like this

def areaOfCircle(radius: Double)(implicit  piValue: Double): Double = piValue * radius * radius

def circumferenceOfCircle(radius: Double)(implicit  piValue: Double): Double = 2 * piValue * radius

Now, below is the complete code snippet

object ImplicitParametersExamples extends App {
  implicit val approxPiValue: Double = 3.14

  def areaOfCircle(radius: Double)(implicit  piValue: Double): Double = piValue * radius * radius

  def circumferenceOfCircle(radius: Double)(implicit  piValue: Double): Double = 2 * piValue * radius

  println(areaOfCircle(5))

  println(circumferenceOfCircle(10))
}

In the above code snippet, you can see that we declared the piValue as an implicit value. And since both methods expect pi Value as an implicit variable, Scala compiler automatically uses approxPiValue and passes it as piValue while calling these methods.

Remember that Scala will use any double value that is in its scope as an implicit value. And in this case it is approxPiValue

Also, in the above example, I can replace approxPiValue with an implicit method that returns double value

implicit def calculatePIValue: Double = 22d/7d

Scala compiler will now resolve piValue from the above value returned by calculatePIValue.

How does Scala Compiler resolve an implicit parameter?

Now, the question is, where does Scala look for implicit parameters? In our above example, there is no ambiguity since we defined the implicit value in the same method. But in practicality it does not make sense defining implicit values in the same method.

Scala compiler tries to find the value in lexical scope failing which it tries next on the implicit scope

Lexical scope

Scala compiler will check for a implicit value of the same type

  • In the same class or object
  • You can also bring implicit values defined in an Object or a trait using import statement

Implicit scope

Scala compiler will next search for implicit values defined in the companion object

What will happen when Scala compiler finds multiple values in lexical or implicit scope? Well, it uses overload resolution algorithm to pick one of them. If the compiler is unable to determine the implicit value, an error is thrown. Let me keep the article simple and assume that compiler finds an implicit value in either of the scopes

We covered implicit parameters because it's the simplest form of implicit. Let us now get into implicit conversions

Implicit conversions

Let us take a different example. Lets say that I want to code a method called vulcanGreeting. This vulcanGreeting will take an argument name and prints the greeting message. Something simple like this,

object VulcanGreet extends App {
  def sayHello(name: String): Unit = println(s"Live long and prosper.... ${name}")

  sayHello("Kirk")
}

Let's do the above example differently. Lets use implicit conversion

object Greetings {
  implicit class VulcanGreeting(name: String) {
    def greetInVulcan = println(s"Live long and prosper... ${name}")
  }
}

import Greetings._
object GreetingsApp extends App {
  "Kirk".greetInVulcan
}

Both the above examples give the same output on the console

Live long and prosper... Kirk

But wait, how am I able to call a method greetInVulcan on a String("Kirk"). There is no such method in String. Welcome to the world of implicit conversions Let's first analyse the below object

object Greetings {
  implicit class VulcanGreeting(name: String) {
    def greetInVulcan = println(s"Live long and prosper... ${name}")
  }
}

The Greetings object defines an implicit class VulcanGreeting. This implicit class takes an argument name. Nothing fancy about this class except for the keyword implicit Now let's examine the second object

import Greetings._
object GreetingsApp extends App {
  "Kirk".greetInVulcan
}

The line import Greetings._ imports all the implicit classes in the object Greetings. Or in other words, the moment you import it, the implicit class VulcanGreeting comes into the lexical scope. Now examine the line "Kirk".greetInVulcan Since the Scala compiler has VulcanGreeting in the scope, it converts String to VulcanGreeting. And allows you to use all the methods in the VulcanGreeting on the String

Implicit are extensively used in Scala. Understanding implicit is also the first step to understand libraries like Cats and Scalaz

The journey from here

When I started using Cats, I realized the path taken to get a gasp of it has been long and challenging. Cats is a wonderful collection of functional programming tools. Type classes, the corner stone of Cats, is a programming pattern borrowed from Haskell. The first step in this journey is to know about Scala Implicit. My objective is to simplify this journey to Functional programming excellence

References

Scala Docs

Cats

Functional Programming Simplified