Nerd For Tech
Published in

Nerd For Tech

Implicit conversion and parameters in Scala

Implicit definitions are those in which compiler is allowed to insert into a program if there are any type errors. In other terms it is a final way to avoid some kind of errors in the code and continue with program execution. Consider the example a+b what happens if a and b are not compatible, of course the compiler will throw an error. But it will be very nice if the compiler tries whether there is any way that a can be converted into a type so that there won’t be any type mismatch, for example change a+b into convert(a) + b.

This is exactly what an implicit does, it checks whether there is any way to convert the type, so that a possible error can be avoided. Compiler follows a set of rules for applying implicit conversion.

Rules for implicit conversion

In the above example in order to apply the method convert(a), there must be such a method defined with a keyword implicit.

implicit def intToString(x: Int) = x.toString

If there is method marked as implicit in the given context of the code the compiler will automatically pick it up, and then conversion is performed.

Scala compiler will only consider the implicit conversion in the given scope, In the above example to apply the convert method you must bring it into the program scope. In order to use the implicit methods in a library we have to explicitly import it first. For example

import scala.preamble._

After importing the package scala.preamble we can use all the implicits defined inside the package. In a way we are bringing the implicits defined, into the current context of execution.

If the compiler is trying to resolve one implicit it is impossible to bring another one into context of execution.

convert1(convert2(x)) + y

Such an implicit conversion is not possible because conver2(x) is in progress.

If the code is already working fine the compiler will not try to change it, this rule can also be taken as we can always covert an implicit with an explicit ones.

There are three methods where implicits are used inside a program they are conversions to an expected type,Conversions of the receiver of selection and implicit parameters now let us check each of these one by one.

1- Conversion to an expected type

If compiler sees type X but it needs to be converted into type Y, then compiler will check for any implicit function, if no such function is available it will throw an error.

scala> val k:Int = 3.6
<console>:11: error: type mismatch;
found : Double(3.6)
required: Int
val k:Int = 3.6

Solution: Define an implicit function to convert double to Int.

scala> implicit def doubleToInt(x: Double) = x.toInt
warning: there was one feature warning; re-run with -feature for details
doubleToInt: (x: Double)Int
scala> val k:Int = 3.6
k: Int = 3

In the above example we can see double type automatically castes into an Integer. This happened because there is an implicit function doubleToInt in the same context. So when we assigned a double type to an Integer

doubleToInt(3.6) is applied and a value of 3 is obtained.

2- Converting the receiver

Implicit type conversion can be applied to the receiver of a method call.

Simulating new syntax

Map(1 -> "one", 2 -> "two", 3 -> "three")

In the above given example have you ever wondered how the operator -> is supported!!! -> is not an operator it is a function defined inside the ArrowAssoc class.

package scala
object Predef {
class ArrowAssoc[A](x: A) {
def -> [B](y: B): Tuple2[A, B] = Tuple2(x, y)
}
implicit def any2ArrowAssoc[A](x: A): ArrowAssoc[A] =
new ArrowAssoc(x)
...
}

When you write 1 -> “One” compiler will automatically convert 1 to ArrowAssoc so that -> method can be found and it can be used.

Implicit classes

An implicit class is simply a class that is declared with an Implicit keyword.

scala> case class Rectangle(width: Int, height: Int)
defined class Rectangle
scala> implicit class RectangleMaker(width: Int) {
| def x(height: Int) = Rectangle(width, height)
|}
defined class RectangleMaker
scala> val myRectangle = 3 x 4
myRectangle: Rectangle = Rectangle(3,4)

There exists no such operator such as x for int, but the compiler will look for an implicit conversion to Int, then it will find the implicit class RectangleMaker and a method x inside RectangleMaker.

3- Implicit parameters

We define a class PreferredPrompt, and an object Greeter with a method greet inside it.

scala> class PreferredPrompt(val preference: String)
defined class PreferredPrompt
scala> object Greeter {
| def greet(name: String)(implicit prompt: PreferredPrompt) = {
| println("Welcome, " + name + ". The system is ready.")
| println(prompt.preference)
| }
| }
defined object Greeter

Now we can provide prompt value explicitly as shown below

scala> val bobsPrompt = new PreferredPrompt("relax> ")
bobsPrompt: PreferredPrompt = PreferredPrompt@1218e12
scala> Greeter.greet("Bob")(bobsPrompt)
Welcome, Bob. The system is ready.
relax>

If we need the compiler to provide the value for PreferredPrompt implicitly, we must define a variable of expected type that is of type PreferredPrompt as shown below.

object JoesPrefs {
implicit val prompt = new PreferredPrompt("Yes, master> ")
}

Then import to JoesPrefs bring it into the context of execution. Compiler will look for an implicit value within the current context of execution if found compiler will use it else it will throw an error.

scala> import JoesPrefs._
import JoesPrefs._
scala> Greeter.greet("Joe")
Welcome, Joe. The system is ready.
Yes, master>

Debugging implicits

Implicits are very powerful features in scala, but sometimes it will be difficult to get it right. Now let us see few tips for debugging errors regarding implicits.

scala> val chars: List[Char] = "xyz"
<console>:17: error: type mismatch;
found : String("xyz")
required: List[Char]
val chars: List[Char] = "xyz"

Now in order to debug the error let us provide wrapString explicitly.

scala> val chars:List[Char] = wrapString("xyz")
<console>:17: error: type mismatch;
found : scala.collection.immutable.WrappedString
required: List[Char]
val chars:List[Char] =wrapString("xyz")

Now we got the error, return type of wrapString doesn't match with type of chars. If we doesn’t got any error after applying the function implicitly then we can infer a violation of scope rule occurred (No implicit method exists within the scope).

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store