Published 2013-09-18.
Last modified 2019-07-23.
Time to read: 6 minutes.
Implicit classes provide extra functionality to value classes.
The sample code for this lecture can be found in
courseNotes/
.
Implicit classes allow the addition of extra functionality onto an existing type without actually modifying the original type. Implicit classes allow business logic to be defined outside of value objects, and provides a form of dependency injection. Implicit classes are just like regular Scala classes, with the following additional rules.
- Implicit classes are decorated with the
implicit
keyword. - Implicit classes must not be top-level objects. You must define them in another object or class.
- Implicit class constructors must receive at least one parameter.
- The only methods in implicit classes that will be considered for implicit conversions are those that do not accept any parameters.
For an alternative to using implicit classes to enrich existing types, see the Parametric Traits as Rich Interfaces section of the Parametric Types lecture.
Simple Example
In the following simple example, an implicit class is defined which wraps an Int
.
Note that the name of this class is never directly referenced in your program because it is implicitly referenced.
This means that the name of the class is completely arbitrary.
In this example, the length
method returns the length of the string representation of the Int
that is passed in.
From the point of view of the programmer when this implicit class is in scope, it seems as if Int
s now
have a method called length
!
However, please note that the definition of Int
has not changed.
All that happens is that the Scala compiler looks around for implicit classes whenever it cannot find a method –
rather like Ruby’s method_missing
mechanism.
I called this class randomName
to emphasize that its name does not matter.
The constructor for this class accepts an Int
.
The class defines a method called length
which returns the number of digits of the int
variable.
scala> implicit class randomName(int: Int) {
| val length: Int = int.toString.length
| }
defined class randomName
Now that the implicit class is defined in the current scope, we can invoke the length
method on any Int
.
scala> 5.length res4: Int = 1
scala> 55.length res4: Int = 2
scala> 555.length res4: Int = 3
At compile time, when the compiler encountered a reference to the length
method, it ’knew’
that no such method is defined for the Int
type.
However, the compiler was aware that the implicit class definition for randomName
was in scope
at that point in the program, so at runtime an instance of randomName
was implicitly created,
the value of the Int
was passed to it, and the randomName.length
method was invoked.
We use the term boxing to denote the process of creating an instance of a holder class such as
randomName
so we can pass a value and invoke a method, and we use the term unboxing to denote the
extraction of the value and the disposing of the holder class.
BTW, notice how I defined the length property as a val
,
because its value does not change after a randomName
instance is created.
Implicit Value Classes
You can define an implicit class as a value class and possibly eliminate boxing and unboxing,
if value class constraints are not a problem for your use case.
We discussed value classes in the Implicit Values lecture.
All we have to do in order to make the implicit class more efficient at runtime is to make it into a value class by
turning each of the constructor parameters into class instance properties (which is what the val
is for),
and to have the class extend AnyVal
.
scala> implicit class randomName2(val long: Long) extends AnyVal { | @inline def length: Int = long.toString.length | } defined class randomName2
scala> 5L.length res4: Int = 1
BTW, you might have been motivated to define the length property as a val
,
because its value does not change after a randomName
instance is created.
However, as we learned in the Implicit Values lecture,
implicit classes are not allowed to contain val
s or var
s,
so I defined it as an @inline def
.
@inline
causes the compiler to emit the JVM byte code from the method definition is emitted each time the
method is invoked, instead of making a method call.
@inline
increases the size of the program slightly, but it runs faster.
Example: IntToUSD
This example has several interesting features that make it lightweight and easy to use.
- The implicit class extends
AnyVal
so theIntToUSD
class need not be instantiated for many / most circumstances. - The default method
apply
is used so no method name need be specified. - @inline is again used to trade off execution speed for program size.
scala> implicit class IntToUSD(val i: Int) extends AnyVal { | @inline def apply(s: String): String = s"$i $s" | } defined class IntToUSD
scala> 100("USD") res5: String = 100 USD
This is the same as writing.
scala> IntToUSD(100).apply("USD") res2: String = 100 USD
Example: SymbolToCurrency
In Scala, a Symbol
is like a String
, but instead of being surrounded by double quotes, until Scala 2.13 it was simply preceded by a single quote.
That means Symbol
instances do not normally have embedded spaces.
Starting with Scala 2.13, the Symbol.apply
default method is the preferred way to create Symbol
instances.
A symbol can be converted to a String
by accessing its name
property.
scala> implicit class SymbolToCurrency(val sym: Symbol) extends AnyVal { | @inline def apply(value: Int): String = s"$value ${ sym.name }" | } defined class SymbolToCurrency
scala> Symbol("USD")(100) res6: String = 100 USD
This is the same as writing:
scala> SymbolToCurrency(Symbol("USD")).apply(100) res7: String = 100 USD
Exercise – What does this print out?
object AppleFanBoi extends App { implicit class IosInt(val i: Int) extends AnyVal { def s: Int = i + 1 }
println(s"I have an iPhone ${4.s}") }
Solution
You can run this program by typing:
$ scala> sbt "runMain solutions.AppleFanBoi"
I have an iPhone 5
“Enhance My Library” / “Extension Method” Pattern

This pattern has been known by several names, including the original (and offensive) "Pimp my library" name.
The functionality defined by Scala’s built-in value types are extended by Scala’s implicit conversions. Some people claim that the use of this pattern is ’the Scala way’, and everyone should consider using to add functionality to domain model classes. This keeps your model separate from your business logic. The downside of using this pattern is that debugging implicit classes is more difficult.
Let’s see how this works by extending the Dog
case class we used earlier, and adding classes Stick
and Ball
.
I defined DogCommands
as an implicit value class because it only contains methods and no variables.
case class Dog(name: String) { override def equals(that: Any): Boolean = canEqual(that) && hashCode==that.hashCode override def hashCode = name.hashCode }
class Stick
case class Ball(color: String)
implicit class DogCommands(val dog: Dog) extends AnyVal { def call(me: String): String = s"Here, ${dog.name} come to $me"
def fetch(stick: Stick): String = s"${dog.name}, fetch the stick!"
def fetch(ball: Ball): String = s"${dog.name}, fetch the ${ball.color} ball!" }
We can use the implicit class this way:
scala> val dog = Dog("Fido") dog: Dog = Dog(Fido)
scala> dog.call("me") res2: String = Here, Fido come to me
scala> dog.fetch(new Stick) res3: String = Fido, fetch the stick!
scala> val ball = new Ball("green") ball: Ball = Ball(green)
scala> dog.fetch(ball) res4: String = Fido, fetch the green ball!
This is similar to how Scala’s RichInt
class (invisible for Scala 2.13.0, hopefully will be fixed for 2.13.1 by moving it to another package)
extends the functionality of the Int
value class using implicits.
You can also run this program like this:
$ sbt "runMain EnhanceMyLibrary"
The Defining Custom String Interpolation to Access a Map section of the Collections Overview lecture shows another example of enriching a class.
Exercise - Enhance Complex
Use the Enhance My Library pattern to add an
absolute value
method to Complex
.
Compute this value by taking the square root of the square of the real part plus the square of the imaginary part.
Hint
Use math.sqrt
to take the square root.
Solution
package solutions
object ImplicitClasses extends App { import solutions.ImplicitCoercion.Complex
implicit class RichComplex(val complex: Complex) extends AnyVal { def abs: Double = math.sqrt(complex.re * complex.re + complex.im * complex.im) }
println(s"Complex(3, 4).abs=${Complex(3, 4).abs}") }
You can run this solution by typing.
$ sbt "runMain solutions.ImplicitClasses" Complex(3, 4).abs=5.0
Exercise – Separating Business Logic from the Domain Model
Define a domain class Weather
that somehow describes the current state of the weather.
Define an implicit class RichWeather
that provides actions like rain()
,
sunshine()
and hurricane()
.
Those methods should change the current state of the weather and print a suitable message.
Run the solution as a console program.
Solution
package solutions
object WeatherMain extends App { case class Weather(var status: String)
implicit class RichWeather(weather: Weather) { def genericOp(newStatus: String): Weather = { weather.status = newStatus println(s"It is now ${weather.status}") weather }
def rain(): Weather = genericOp("raining")
def hail(): Weather = genericOp("hailing")
def sunshine(): Weather = genericOp("shining") }
val weather = Weather("shining") weather.rain() weather.hail() weather.sunshine() }
To run, type:
$ sbt "runMain solutions.WeatherMain" It is now raining It is now hailing It is now shining
Where to Put Implicit Definitions?

Enriched classes are typically defined in a separate package from the value objects that they enrich.
This is also true for implicit conversions.
Normally you should limit the scope of implicit definitions.
If the implicits are merely required for a class or trait, then define them in the companion object and import them.
If the implicits are required for an entire package, they could be defined in a package
object
.
However if the implicit definitions were also required in other packages you might not want to drag in the other
definitions in the package
object
.
Instead you can make the implicits available as required by defining them within another object and by explicitly importing them when required.
You can also define implicits in traits that are mixed in as required.
There are a variety of ways to set this up. Implicit classes were introduced with Scala 2.10; prior to that the same capability required a more complex setup to achieve a similar result. Lets look at the source code of a few large open-source projects to see how this was done; the links will take you to the source code on GitHub.
-
The Scala runtime uses the
Predef
object as the gathering point for numerous default implicits.Predef
is automatically included into every Scala program.Scala codeobject Predef extends LowPriorityImplicits
Predef
defines explicit conversions that wrap the type to be enriched, like this:Scala code@inline implicit def intWrapper(x: Int) = new runtime.RichInt(x)
@inline
, which means that this acts more like a C-language macro expansion than a method call. -
scala.jdk.CollectionConverters
, discussed in the To Converters lecture, follows a pattern used when there are many implicit conversions;AsJavaExtensions
withAsScalaExtensions
actually define the implicits:Scala codeobject CollectionConverters extends AsJavaExtensions with AsScalaExtensions
Comprehensive Example (Supplemental)

This example defines an implicit class called SymbolLookup
which converts Scala
Symbol
s
to currency exchange rates.
A Symbol
is like a unique string, and is often written by prefacing it with a single quote.
Symbol
s should not be defined with embedded spaces.
Once the implicit class is explicitly imported it can be used as follows.
object Rates extends App { import SymbolToCurrency._
println(Symbol("CAD")(100.0)) println(’USD(100.0)) println(’JPY(100.0)) println(’BLA(100.0)) }
Typical output is:
126.1808 CAD 100.0 USD 11941.849999999999 JPY Currency BLA unknown. Available currencies are: AED, AFN, ALL, AMD, ANG, AOA, ARS, AUD, AWG, AZN, BAM, BBD, BDT, BGN, BHD, BIF, BMD, BND, BOB, BRL, BSD, BTC, BTN, BWP, BYR, BZD, CAD, CDF, CHF, CLF, CLP, CNY, COP, CRC, CUC, CUP, CVE, CZK, DJF, DKK, DOP, DZD, EEK, EGP, ERN, ETB, EUR, FJD, FKP, GBP, GEL, GGP, GHS, GIP, GMD, GNF, GTQ, GYD, HKD, HNL, HRK, HTG, HUF, IDR, ILS, IMP, INR, IQD, IRR, ISK, JEP, JMD, JOD, JPY, KES, KGS, KHR, KMF, KPW, KRW, KWD, KYD, KZT, LAK, LBP, LKR, LRD, LSL, LTL, LVL, LYD, MAD, MDL, MGA, MKD, MMK, MNT, MOP, MRO, MTL, MUR, MVR, MWK, MXN, MYR, MZN, NAD, NGN, NIO, NOK, NPR, NZD, OMR, PAB, PEN, PGK, PHP, PKR, PLN, PYG, QAR, RON, RSD, RUB, RWF, SAR, SBD, SCR, SDG, SEK, SGD, SHP, SLL, SOS, SRD, STD, SVC, SYP, SZL, THB, TJS, TMT, TND, TOP, TRY, TTD, TWD, TZS, UAH, UGX, USD, UYU, UZS, VEF, VND, VUV, WST, XAF, XAG, XAU, XCD, XDR, XOF, XPF, YER, ZAR, ZMK, ZMW, ZWL
Here is the implicit class defined inside the SymbolToCurrency
object
:
implicit class SymbolLookup(val symbol: Symbol) extends AnyVal { @inline def apply(value: Double): String = try { val convertedValue = value * rateMap(symbol) s"$convertedValue ${symbol.name}" } catch { case nsee: NoSuchElementException => println(s"Currency ${symbol.name} unknown. Available currencies are: ${rateMap.keys.map(_.name).toSeq.sorted.mkString(", ")}") "" } }
This code relies on the OpenExchangeRates.org
API, which returns JSON.
You will need your own OpenExchange key in order to run this code example; there is no charge for a developer key.
Because we don’t cover JSON in this course, I used a regular expression
(Regex) to parse the JSON.
The Scala I/O lecture will explain how the io.Source.fromURL
method works.
protected val openExchangeKey = sys.env("OPEN_EXCHANGE_KEY") protected val urlStr = s"https://openexchangerates.org/api/latest.json?app_id=$openExchangeKey" protected val latestRates: String = io.Source.fromURL(urlStr).mkString protected val RateRegex = """(?s)rates.: \{(.*?)\}""".r.unanchored protected val RateRegex(rates) = latestRates
rates
is a String
, which is parsed into a List[(Symbol, Double)]
, and is stored as rateTuples
.
The For-Loops and For-Comprehensions and
For-Loops and For-Comprehensions Examples lectures will explain the for-comprehension.
protected val rateTuples: List[(Symbol, Double)] = (for { rateStr <- rates.split(",").toList } yield { rateStr.replaceAll("[ \n\"]", "").split(":") match { case Array(k, v) => try { Some(Symbol(k) -> v.toDouble) } catch { case e: Exception => println(s"${e.getClass.getName} while parsing $v: ${e.getMessage}; ignored") None }
case wat => println(s"$wat could not be parsed, ignored") None } }).flatten
rateMap
is then created from rateTuples
, and is now available for lookups using the default method apply
.
Map
s will be discussed in the Collections Overview lecture.
protected val rateMap: Map[Symbol, Double] = rateTuples.toMap
def apply(symbol: Symbol): Double = rateMap(symbol)
To run, type:
$ export OPEN_EXCHANGE_KEY=7364734638483498732987423 // this is a bogus key $ sbt "runMain Rates"
Output is as shown above.
© Copyright 1994-2024 Michael Slinn. All rights reserved.
If you would like to request to use this copyright-protected work in any manner,
please send an email.
This website was made using Jekyll and Mike Slinn’s Jekyll Plugins.