Tour of Scala

Implicit Conversions

Language

Implicit conversions are a powerful Scala feature that enable two common use cases:

  • allow users to supply an argument of one type, as if it were another type, to avoid boilerplate.
  • in Scala 2, to provide additional members to closed classes (replaced by extension methods in Scala 3).

Detailed Explanation

In Scala 2, an implicit conversion from type S to type T is defined by either an implicit class T that has a single parameter of type S, an implicit value which has function type S => T, or by an implicit method convertible to a value of that type.

In Scala 3, an implicit conversion from type S to type T is defined by a given instance which has type scala.Conversion[S, T]. For compatibility with Scala 2, they can also be defined by an implicit method (read more in the Scala 2 tab).

Implicit conversions are applied in two situations:

  1. If an expression e is of type S, and S does not conform to the expression’s expected type T.
  2. In a selection e.m with e of type S, if the selector m does not denote a member of S.

In the first case, a conversion c is searched for, which is applicable to e and whose result type conforms to T.

An example is to pass a scala.Int, e.g. x, to a method that expects scala.Long. In this case, the implicit conversion Int.int2long(x) is inserted.

In the second case, a conversion c is searched for, which is applicable to e and whose result contains a member named m.

An example is to compare two strings "foo" < "bar". In this case, String has no member <, so the implicit conversion Predef.augmentString("foo") < "bar" is inserted. (scala.Predef is automatically imported into all Scala programs.)

How are implicit conversions brought into scope?

In Scala 2, an implicit conversion is brought into scope by importing from the object that defined it, (e.g. Conversions in this case). If the implicit conversion is in the companion object of the argument type, (e.g. Student in this case), then no import is necessary.

import scala.language.implicitConversions // required to define an implicit conversion

case class Student(name: String)
object Student {
  implicit def fromStudentToInt(student: Student): Int = student.name.length
}
  
object Conversions {
  implicit def fromStringToStudent(name: String): Student = Student(name)
}

import Conversions._
object Usage {
  def main(args: Array[String]) = {
    val reginald: Student = "Reginald" // applies the conversion Conversions.fromStringToStudent
    println(reginald + 2)              // applies the conversion Student.fromStudentToInt
  }
}

In Scala 3, an implicit conversion is brought into scope by either importing given or the named conversion from the object that defined it, (e.g. Conversions in this case).

Note that as of Scala 3, implicit conversions cannot be brought into scope anymore by means of a wildcard import (*).

Given the example:

case class Student(name: String):
  def printName: Unit = println(name)
object Student:
  given Conversion[Student, Int] = _.name.length
  
object Conversions:
  given fromStringToStudent: Conversion[String, Student] = Student(_)

The following imports would bring the Conversion[String, Student] into scope:

  • import Conversions.given
  • import Conversions.{given Conversion[String, Student]}
  • import Conversions.fromStringToStudent

If the implicit conversion is in the companion object of the argument type, (e.g. Student in this case), then no import is necessary.

import Conversions.given
object Usage:
  @main def run =
    val reginald: Student = "Reginald" // applies the Conversion[String, Student]
    println(reginald + 2)              // applies the Conversion[Student, Int]

Further reading:

Beware the power of implicit conversions

Because implicit conversions can have pitfalls if used indiscriminately the compiler warns when compiling the implicit conversion definition.

To turn off the warnings take either of these actions:

  • Import scala.language.implicitConversions into the scope of the implicit conversion definition
  • Invoke the compiler with -language:implicitConversions

No warning is emitted when the conversion is applied by the compiler.

Because implicit conversions can have pitfalls if used indiscriminately the compiler warns in two situations:

  • when compiling a Scala 2 style implicit conversion definition.
  • at the call site where a given instance of scala.Conversion is inserted as a conversion.

To turn off the warnings take either of these actions:

  • Import scala.language.implicitConversions into the scope of:
    • a Scala 2 style implicit conversion definition
    • call sites where a given instance of scala.Conversion is inserted as a conversion.
  • Invoke the compiler with -language:implicitConversions

Contributors to this page: