Implicit conversions are a powerful Scala feature that allows users to supply an argument of one type as if it were another type, to avoid boilerplate.
Note that in Scala 2, implicit conversions were also used to provide additional members to closed classes (see Implicit Classes). In Scala 3, we recommend to address this use-case by defining extension methods instead of implicit conversions (although the standard library still relies on implicit conversions for historical reasons).
Example
Consider for instance a method findUserById
that takes a parameter of type Long
:
def findUserById(id: Long): Option[User]
We omit the definition of the type User
for the sake of brevity, it does not matter for
our example.
In Scala, it is possible to call the method findUserById
with an argument of type Int
instead of the expected type Long
, because the argument will be implicitly converted
into the type Long
:
val id: Int = 42
findUserById(id) // OK
This code does not fail to compile with an error like “type mismatch: expected Long
,
found Int
” because there is an implicit conversion that converts the argument id
to a value of type Long
.
Detailed Explanation
This section describes how to define and use implicit conversions.
Defining an Implicit Conversion
In Scala 2, an implicit conversion from type S
to type T
is defined by an
implicit class T
that takes
a single constructor parameter of type S
, an
implicit value of
function type S => T
, or by an implicit method convertible to a value of that type.
For example, the following code defines an implicit conversion from Int
to Long
:
import scala.language.implicitConversions
implicit def int2long(x: Int): Long = x.toLong
This is an implicit method convertible to a value of type Int => Long
.
See the section “Beware the Power of Implicit Conversions” below for an
explanation of the clause import scala.language.implicitConversions
at the beginning.
In Scala 3, an implicit conversion from type S
to type T
is defined by a
given
instance
of type scala.Conversion[S, T]
. For compatibility with Scala 2, it can also
be defined by an implicit method (read more in the Scala 2 tab).
For example, this code defines an implicit conversion from Int
to Long
:
given int2long: Conversion[Int, Long] with
def apply(x: Int): Long = x.toLong
Like other given definitions, implicit conversions can be anonymous:
given Conversion[Int, Long] with
def apply(x: Int): Long = x.toLong
Using an alias, this can be expressed more concisely as:
given Conversion[Int, Long] = (x: Int) => x.toLong
Using an Implicit Conversion
Implicit conversions are applied in two situations:
- If an expression
e
is of typeS
, andS
does not conform to the expression’s expected typeT
. - In a selection
e.m
withe
of typeS
, if the selectorm
does not denote a member ofS
(to support Scala-2-style extension methods).
In the first case, a conversion c
is searched for, which is applicable to e
and whose result type conforms to T
.
In our example above, when we pass the argument id
of type Int
to the method findUserById
,
the implicit conversion int2long(id)
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?
When the compiler searches for applicable conversions:
- first, it looks into the current lexical scope
- implicit conversions defined in the current scope or the outer scopes
- imported implicit conversions
- implicit conversions imported by a wildcard import (Scala 2 only)
- then, it looks into the companion objects associated with the argument
type
S
or the expected typeT
. The companion objects associated with a typeX
are:- the companion object
X
itself - the companion objects associated with any of
X
’s inherited types - the companion objects associated with any type argument in
X
- if
X
is an inner class, the outer objects in which it is embedded
- the companion object
For instance, consider an implicit conversion fromStringToUser
defined in an
object Conversions
:
import scala.language.implicitConversions
object Conversions {
implicit def fromStringToUser(name: String): User = User(name)
}
object Conversions:
given fromStringToUser: Conversion[String, User] = (name: String) => User(name)
The following imports would equivalently bring the conversion into scope:
import Conversions.fromStringToUser
// or
import Conversions._
import Conversions.fromStringToUser
// or
import Conversions.given
// or
import Conversions.{given Conversion[String, User]}
Note that in Scala 3, a wildcard import (ie import Conversions.*
) does not import given
definitions.
In the introductory example, the conversion from Int
to Long
does not require an import
because it is defined in the object Int
, which is the companion object of the type Int
.
Further reading: Where does Scala look for implicits? (on Stackoverflow).
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