1. Overview

In this tutorial, we’ll learn about implicit conversions. We’ll see how they reduce boilerplate code and how they can be used to add additional methods to existing classes.

2. Implicit Conversions

Implicit conversions give the Scala compiler the ability to convert one type into another.

We can also use them to add additional methods to existing classes. However, since Scala 2.10, we should use implicit classes for this use case.

3. A Length Use Case

Let’s imagine that we have different types that represent length units:

case class Centimeters(value: Double) extends AnyVal
case class Meters(value: Double) extends AnyVal
case class Kilometers(value: Double) extends AnyVal

We would like to use them interchangeably without any boilerplate code.

4. Implicit Conversion Method

If we want to use Meters in places where Centimeters are required, we need to provide an implicit conversion from Meters into Centimeters. We can do it by creating an implicit method, which takes Meters and returns Centimeters:

implicit def meters2centimeters(meters: Meters): Centimeters =
  Centimeters(meters.value * 100)

val centimeters: Centimeters = Meters(2.5)

centimeters shouldBe Centimeters(250)

The Scala compiler knows that Meters is not a subtype of Centimeters. However, instead of a compilation error, it checks if there is an implicit conversion available that converts Meters into Centimeters.

Therefore we have provided an implicit meters2centimeters method, we are able to assign the Meters(2.5) to variable centimeters of type Centimeters.

5. Implicit Conversion Function

An implicit function is another way of providing an implicit conversion:

implicit val kilometers2meters: Kilometers => Meters =
  kilometers => Meters(kilometers.value * 1000)

val meters: Meters = Kilometers(2.5)

meters shouldBe Meters(2500)

This time we have provided an implicit kilometers2meters function and are now able to treat Kilometers as Meters.

6. Extension Methods

An implicit conversion can also be used to add additional methods to existing classes. So let’s add centimeters, meters, and kilometers methods for creating length units to Double:

class LengthSyntax(value: Double) {
  def centimeters = Centimeters(value)
  def meters = Meters(value)
  def kilometers = Kilometers(value)
}

implicit def double2richSyntax(value: Double): LengthSyntax =
  new LengthSyntax(value)

val length: Double = 2.5

length.centimeters shouldBe Centimeters(length)
length.meters shouldBe Meters(length)
length.kilometers shouldBe Kilometers(length)

In this case, the compiler is looking for an implicit conversion that converts Double into anything that has centimeters, meters, or kilometers methods. Therefore we provided an implicit double2richSyntax method, and the compiler knows what to do.

7. Limitations

Unfortunately, implicit conversions have some limitations:

  • They cannot take multiple non-implicit arguments
  • They cannot chain multiple implicit conversions

7.1. Non-implicit Arguments

They cannot take multiple non-implicit arguments:

implicit def meters2centimeters(meters: Meters, secondArg: Boolean): Centimeters =
  Centimeters(meters.value * 100)

val centimeters: Centimeters = Meters(2.5)

The above code won’t compile because we added the second non-implicit argument. The compiler is not able to treat Meters as Centimeters:

[error] type mismatch;
[error] found : com.baeldung.scala.implicitconversions.Meters
[error] required: com.baeldung.scala.implicitconversions.Centimeters
[error] val centimeters: Centimeters = Meters(2.5)

However, having an additional implicit argument is not a problem:

implicit val boolean = true
implicit def meters2centimeters(meters: Meters)(implicit secondArg: Boolean): Centimeters =
  Centimeters(meters.value * 100)

val centimeters: Centimeters = Meters(2.5)

7.2. Chain Implicit Conversions

We cannot chain multiple implicit conversions:

implicit def kilometers2meters(kilometers: Kilometers): Meters =
  Meters(kilometers.value * 1000)
implicit def meters2centimeters(meters: Meters): Centimeters =
  Centimeters(meters.value * 100)

val centimeters: Centimeters = Kilometers(2.5)

The Scala compiler can take only one implicit conversion into consideration. Consequently, we cannot assign Kilometers into a centimeters variable of Centimeters type:

[error] type mismatch;
[error] found : com.baeldung.scala.implicitconversions.Kilometers
[error] required: com.baeldung.scala.implicitconversions.Centimeters
[error] val centimeters: Centimeters = Kilometers(2.5)

Although, we can have implicit conversions from Kilometers into Meters and Meters into Centimeters.

8. Warnings

As we saw, implicit conversions have great powers. Nonetheless, with great power comes great responsibility. Therefore the Scala compiler will always warn us about using implicit conversions:

[warn] implicit conversion method meters2centimeters should be enabled

We can enable implicit conversion in the whole project by setting the compiler option in our build.sbt:

scalacOptions += "-language:implicitConversions"

On the other hand, if we want to enable it only for a particular class or method we can do it using a single import:

import scala.language.implicitConversions

9. Conclusion

In this short article, we explored implicit conversionsWe saw how they reduce boilerplate code and how they can be used to add methods to existing classes.

As always, the full source code of the article is available over on GitHub.

Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments