Mike Slinn

Implicit Values

— Draft —

Published 2013-09-18. Last modified 2019-10-09.
Time to read: 10 minutes.

Implicit values simplify API usage. Value classes are also introduced, which can provide type safety without incurring runtime overhead.

Git Clone the Course Notes

The sample code for this lecture can be found in courseNotes/src/main/scala/ImplicitValues.scala.

The quickest way to get a copy of the git repository with the course notes for this project is to type the following in a console with the current directory set to where you want to work with this course.

Shell
$ git clone https://github.com/mslinn/course_scala_intermediate_code_new

This creates a subdirectory called course_scala_intermediate_code_new.

You can update your copy of the course notes at any time by typing the following into a shell prompt in the same course_scala_intermediate_code directory:

Shell
$ git pull origin master

As with the previous course, I show code throughout this course that can be pasted into the REPL, and that code is also provided in the courseNotes directory. You can choose to run the sample code as standalone programs, or you can paste it into the REPL to play with, or you can paste it into a Scala worksheet.

Refer to Lecture Transcripts

When this course is updated, the transcripts are updated first, and then the videos are updated. Sometimes an appreciable amount of time might pass between updating a transcript and updating the corresponding video, or both might be updated simultaneously, depending on the material.

This Lecture Introduces Two Concepts

The two concepts introduced in this lecture are distinct and are completely independent. Here is a high-level description of this lecture’s two main points; do not worry if the description of concept #2 does not make sense yet, it will be fully explored in this lecture.

It is a common object-oriented (OO) design error to just use raw types like Strings and Ints for lesser domain objects like record ids, map keys, counters, etc. Java, Ruby and Python programmers have been taught to use primitive types and low-level classes because in those languages, classes incur a runtime penalty. Scala 2.11 introduced value classes, which if properly used provide type safety without incurring OO overhead at runtime for many common scenarios. Scala value classes encourage better OO designs because there is no longer any reason to use raw types.

Implicit values become much more useful when they are strongly typed instead of being defined as just Ints or Strings. That is because implicit values match on types; the more specific the implicit value’s type, the more robust the design will be.

Combining both concepts: Implicit values that are also value objects also do not incur a runtime overhead in many / most circumstances.

What is an Implicit Value?

Implicit values allow missing method parameters to be found in the runtime context. This means implicit values are useful for simplifying APIs. Both the object being supplied as an implicit parameter and the method signature must be decorated with the word implicit.

Scala code
implicit val defaultMultiplier = 2
def multiply(value: Int)(implicit multiplier: Int): Int = value * multiplier

Note that multiply has two parameter lists, and that the second is prefaced with the word implicit. This is because if a parameter in a list is implicit, all parameters in that list become implicit. Only the last parameter list may be implicit. Let’s see how to use the above definitions.

Scala REPL
scala> multiply(2)(3)
res0: Int = 6
scala>
multiply(5) res1: Int = 10

The above code can be run like this, as discussed in the SBT Project Setup and SBT Tasks and Settings lectures of the Introduction to Scala course.

Shell
$ sbt "runMain ImplicitValues"

Following the uniform access principle (discussed in the Setters, Getters and the Uniform Access Principle lecture of the Introduction to Scala course), vals, vars and defs may all be marked implicit, however implicit methods have a special use, as we shall learn in the next lecture (Implicit Conversions).

If multiple implicitly defined objects are available, the first matching object found in the following search order will be used: local scope, enclosing class, parent class, and companion object. The companion object was discussed in the Objects lecture of the Introduction to Scala course.

Note that implicit values can only exist within a specific scope, and cannot be top-level entities; they must be members of a trait, class or object.

Managing Implicit Values

Define wrapper types when you wish to provide common value types as implicits

The above example shows an implicit of type Int being used in a code fragment. This works fine for small programs, however imagine a much larger program that has many implicits of type Int, used for various purposes. It would be difficult to identify which implicit that should be used because the Scala compiler matches implicits based on type. Let’s rewrite the above so it uses a wrapper class to allow us to identify the Int values we wish to target to implicit parameters. This writing style is more appropriate for a large-scale program. To drive the point home, we introduce another operation, division, which also requires an implicit Int. The Divider wrapper class clarifies the Int that should be used when resolving implicits. Using the REPL.

Scala code
case class Multiplier(value: Int)
case class Divider(value: Int)
implicit val defaultMultiplier = Multiplier(2)
implicit val defaultDivider = Divider(3)
def multiply(value: Int)(implicit multiplier: Multiplier): Int = value * multiplier.value
def divide(value: Int)(implicit divider: Divider): Int = value / divider.value

Now we can use the above just the same as before.

Scala REPL
scala> multiply(2)(Multiplier(3))
res2: Int = 6
scala>
multiply(5) res3: Int = 10
scala>
divide(12)(Divider(4)) res4: Int = 3
scala>
divide(9) res5: Int = 3

The rules for where implicits may be defined and how they are resolved are bent a bit by the REPL. The only way to find out what is actually legal is to write a real Scala program. Let’s recast the above as an actual Scala program.

Scala code
object ImplicitValues2 extends App {
  implicit val defaultMultiplier = Multiplier(2)
implicit val defaultDivider = Divider(3)
def multiply(value: Int)(implicit multiplier: Multiplier): Int = value * multiplier.value
def divide(value: Int)(implicit divider: Divider): Int = value / divider.value
println(s"multiply(2)(Multiplier(3))=${multiply(2)(Multiplier(3))}") println(s"multiply(5)=${multiply(5)}") println(s"divide(12)(Divider(4))=${divide(12)(Divider(4))}") println(s"divide(9)=${divide(9)}") }

You can run this code as follows:

Shell
$ sbt "runMain ImplicitValues2"
multiply(2)(Multiplier(3))=6
multiply(5)=10
divide(12)(Divider(4))=3
divide(9)=3 

The next lecture will show how we can rewrite the above so Ints get converted to Multipliers and Dividers automatically, as required.

Accessing the Implicit Value in Scope

Sometimes you need to obtain the implicit value selected by the compiler for a given type. The implicitly function can provide that implicit value to you.

We can use implicitly to search for an implicit value of type Multiplier and assign it to a variable called m.

Scala REPL
scala> val m = implicitly[Multiplier]
m: Multiplier = Multiplier(2) 

Now lets look for an implicit value that does not exist. For example, let’s search for an implicit value of type Int and attempt to assign it to c.

Scala REPL
scala> val c = implicitly[Int]
<console>:6: error: could not find implicit value for parameter e: Int
       val c = implicitly[Int] 

The error is confusing. In the code shown there is no parameter called e.

Using implicitly To Resolve Implicit Parameters

If multiple implicit parameters are passed to a method, they must co-exist in the same parameter list, and that parameter list must be the last. For example, here is a case class that accepts two parameter lists. The first parameter list accepts an Int called a, and a String called b. The implicit parameter list follows the first parameter list, and it accepts an instance of a java.util.Date and a Multiplier.

Scala code
case class ImplicitDemo(a: Int, b: String)(implicit date: java.util.Date, multiplier: Multiplier)

Let’s say that an implicit Multiplier instance is in scope, but no implicit Date instance is available. In order to create an instance of ImplicitDemo an instance of Date will have to be provided explicitly. However, if one value of an implicit parameter list is provided than all of the other values in the parameter list must also be explicitly provided. The way to do this is to use implicitly to obtain the other implicit values in scope.

Scala code
ImplicitDemo(1, "two")(new Date, implicitly[Multiplier])

@implicitNotFound

This is another reason to use a strongly typed implicit: because you can specify a custom error message when an implicit is not found.

Let’s do that with Multiplier2 and Divider2: by using the @implicitNotFound annotation.

Scala code
import annotation.implicitNotFound
@implicitNotFound("Cannot find implicit of type Multiplier2 in scope") case class Multiplier2(value: Int)
@implicitNotFound("Cannot find implicit of type Divider2 in scope") case class Divider2(value: Int)

@implicitNotFound can be applied to all kinds of classes and traits. Here is how it works.

Scala REPL
scala> implicitly[Multiplier2]
<console>:16: error: Cannot find implicit of type Multiplier2 in scope
              implicitly[Multiplier2]
                        ^ 

Value Classes

Multiplier and Divider require a new object allocation each time an instance is created; this is known as "boxing". Referencing the wrapped value requires "unboxing". The boxing and unboxing can be avoided by deriving the wrapper classes from AnyVal, which is the parent of all value classes. Recall that a value class simply contains a single value. Examples of value classes include Int and String. Value class constructors can only accept one val parameter, which is the underlying runtime representation. We can modify Multiplier and Divider to become value classes by having them extend AnyVal, like this.

Scala code
case class Multiplier3(value: Int) extends AnyVal
case class Divider3(value: Int) extends AnyVal

Now Ints can be converted to Multiplier3 and Divider3 instances without boxing and unboxing, because the runtime representation of value classes is actually the primitive type (Int). Once the references to Multiplier and Divider are changed to Multiplier3 and Divider3, no other changes are required to the rest of the program. You can run the version of the sample code which uses value classes like this.

Shell
$ sbt "run-main ImplicitValues3"

By the way, you can define value classes as regular classes, if you prefer. Just be sure to make the value a property by decorating it with val.

Scala code
object ImplicitValues4 extends App {
  @implicitNotFound("Cannot find implicit of type Multiplier4 in scope")
  class Multiplier4(val value: Int) extends AnyVal
@implicitNotFound("Cannot find implicit of type Divider4 in scope") class Divider4(val value: Int) extends AnyVal
implicit val defaultMultiplier = new Multiplier4(2)
implicit val defaultDivider = new Divider4(3)
def multiply(value: Int)(implicit multiplier: Multiplier4): Int = value * multiplier.value
def divide(value: Int)(implicit divider: Divider4): Int = value / divider.value
println(s"multiply(2)(3)=${multiply(2)(new Multiplier4(3))}") println(s"multiply(5)=${multiply(5)}") println(s"divide(12)(4)=${divide(12)(new Divider4(4))}") println(s"divide(9)=${divide(9)}") }

You can run the version of the sample code which uses value classes that are not case classes like this.

Shell
$ sbt "run-main ImplicitValues4"

Finally, value classes may not contain internally defined variables. For example, this generates a compiler error:

Scala code
class Multiplier4(val value: Int) extends AnyVal {
  val x = 1
}

Value classes have numerous limitations, and may require allocation (leading to boxing/unboxing) in many circumstances. This means that benchmarking your application may reveal that value classes provide no benefit while imposing awkward limitations. The use case presented here, typesafe default values delivered via implicits, without any further manipulation of those values, is a good use of value classes.

Value classes may improve if SIP-35 (Opaque Types) is accepted.

Exercise: Implicit Single Parameter List

This exercise will show you an implementation quirk of Scala’s implicit values. Modify the ImplicitValues4 program above and add a new operation called square. This new method only accepts one parameter, which is implicit, that is the value to square. The method signature should be:

Scala code
def square(implicit squarer: Squarer): Int

Hint

  1. The quirk is this: to call the new square method such that it picks up the implicit value currently in scope, simply type the name of the method without using any parentheses, like this:
    Scala code
    square

Solution

Shell
package solutions
import scala.annotation.implicitNotFound
object ImplicitValues extends App { @implicitNotFound("Cannot find implicit of type Multiplier4 in scope") class Multiplier4(val value: Int) extends AnyVal
@implicitNotFound("Cannot find implicit of type Divider4 in scope") class Divider4(val value: Int) extends AnyVal
@implicitNotFound("Cannot find implicit of type Squarer in scope") class Squarer(val value: Int) extends AnyVal
implicit val defaultMultiplier = new Multiplier4(2)
implicit val defaultDivider = new Divider4(3)
implicit val defaultSquarer = new Squarer(4)
def multiply(value: Int)(implicit multiplier: Multiplier4): Int = value * multiplier.value
def divide(value: Int)(implicit divider: Divider4): Int = value / divider.value
def square(implicit squarer: Squarer): Int = squarer.value * squarer.value
println(s"multiply(2)(3)=${multiply(2)(new Multiplier4(3))}") println(s"multiply(5)=${multiply(5)}") println(s"divide(12)(4)=${divide(12)(new Divider4(4))}") println(s"divide(9)=${divide(9)}") println(s"square(5)=${square(new Squarer(5))}") println(s"square=${square}") }

To run this solution, type.

Shell
$ sbt "runMain solutions.ImplicitValues"

Strongly Typed Method Parameters

This code example mirrors the structure of database access from Scala, without actually using a database.

The sample code for this lecture can be found in courseNotes/src/main/scala/ValueClasses.scala.

Imagine you need to define a method that grants permissions to a User. Let’s use the following Java enum for the permission levels. We discussed various options for defining enumerated values in the Enumerations lecture of the Introduction to Scala course.

Scala code
public enum Permission { GUEST, CHILD, PARENT }

Assuming that there is a User type defined, here is a Users object that resembles how we might access a database. Notice the private mutable collection, and the two methods: add (which returns the Users object so method calls can be chained) and findByName.

Scala code
object Users {
  private val users = ListBuffer.empty[User]
def add(user: User) = { users += user this }
def findByName(name: String): Option[User] = users.find(_.name==name).headOption }

Weakly Typed Code Example

User could be defined like this:

Scala code
case class User(name: String, permissions: Seq[Permission], id: Option[Int]=None)

Here is a weakly typed method authorize definition. It is weakly typed because granteeName is a String.

Scala code
implicit class RichUser(user: User) {
  def authorize(granteeName: String, permission: Permission): Option[User] =
    for {
      grantor <- Some(user) if user.permissions.contains(PARENT)
      grantee <- Users.findByName(granteeName).headOption
    } yield grantee.copy(permissions = grantee.permissions :+ permission)
}

Now we can create two User instances and add them to the Users collection. Note that User wilma has the PARENT permission, but User pebbles has no permissions.

Scala code
val wilma = User("Wilma Flintstone", List(PARENT), Some(1))
val pebbles = User("Pebbles Flintstone", Nil, Some(2))
Users.add(wilma).add(pebbles)

User wilma can now grant the CHILD permission to pebbles.

Scala code
wilma.authorize(pebbles.name, CHILD) match {
  case Some(child) =>
    println(s"${child.name} got upgraded permissions")
case None => println("Authorization failed") }

However, there is nothing to prevent someone from getting confused and writing code that attempts to have pebbles grant CHILD permission to wilma instead.

Scala code
pebbles.authorize(wilma.name, CHILD) match {
  case Some(child) =>
    println(s"${child.name} got upgraded permissions")
case None => println("Authorization failed") }

You can run this program by typing:

Shell
$ sbt "runMain WeaklyTypedParameters"
Pebbles Flintstone got upgraded permissions
Authorization failed 

Strongly Typed Code Example

Let’s define User wrapper value types for Grantor and Grantee, and add methods to User that wraps the User instance in the desired value type.

Scala code
import collection.mutable.ListBuffer
import Permission._
case class User(name: String, permissions: Seq[Permission], id: Option[Int]=None) { def asGrantee: Grantee = Grantee(this)
def asGrantor: Grantor = Grantor(this) }
case class Grantor(user: User) extends AnyVal { def authorize(grantee: Grantee, permission: Permission): Option[Grantee] = { if (user.permissions.contains(PARENT)) Some(grantee.withPermission(permission)) else None } }
case class Grantee(user: User) extends AnyVal { def withPermission(permission: Permission): Grantee = { val newUser = User(user.name, user.permissions :+ permission, user.id) Grantee(newUser) } }

Now we can create mother Wilma and daughter Pebbles, and add them to the Users collection as before.

Scala code
val wilma = User("Wilma Flintstone", List(PARENT), Some(1))
val pebbles = User("Pebbles Flintstone", Nil, Some(2))
Users.add(wilma).add(pebbles)

Here is where we explicitly state the role that we want each user to take on (Grantor or Grantee).

Scala code
wilma.asGrantor.authorize(pebbles.asGrantee, CHILD) match {
  case Some(Grantee(child)) =>
    println(s"${child.name} now has permissions ${child.permissions.mkString(", ")}")
case None => println("Authorization failed") }

This means that the following logic error will not compile:

Scala code
pebbles.asGrantee.authorize(wilma.asGrantor, CHILD) match {
  case Some(child) =>
    println((s"${child.name} now has permissions ${child.permissions.mkString(", ")}")
case None => println("Authorization failed") }

You can run this program by typing:

Shell
$ sbt "runMain StronglyTypedParameters"
Pebbles Flintstone now has permissions CHILD 

’With’ Pattern Using Implicits

As we saw in the More Fun With Functions lecture of the Introduction to Scala course, the With Pattern is common used in Scala; again, this is my name for the pattern – that name is not widely recognized. Let’s modify the example we used to include implicit values.

Scala code
case class Blarg(i: Int, s: String)
def withBlarg(blarg: Blarg)(operation: Blarg => Unit): Unit = operation(blarg)
def double(implicit blarg: Blarg): Blarg = blarg.copy(i=blarg.i*2, s=blarg.s*2)
def triple(implicit blarg: Blarg): Blarg = blarg.copy(i=blarg.i*3, s=blarg.s*3)

The above code looks very much like what we saw in the previous course. This code does not yet take advantage of the implicit parameters defined for the double and triple methods.

Scala REPL
scala> withBlarg(Blarg(1, "asdf")) { blarg =>
     |   println(double(blarg))
     |   println(triple(blarg))
     | }
Blarg(2,asdf asdf)
Blarg(3,asdf asdf asdf) 

If we decorate the blarg reference passed into the closure with implicit, we can rewrite as follows (see the Closures lecture of the Introduction to Scala course to refresh your memory of what a closure is).

Scala REPL
scala> withBlarg(Blarg(1, "qwer")) { implicit blarg =>
     |   println(double)
     |   println(triple)
     | }
Blarg(2,qwer qwer)
Blarg(3,qwer qwer qwer) 

You can arbitrarily decorate the incoming parameter(s) with implicit any time you see a With Pattern being used. The author of withBlarg does not know or care if you decorate the incoming Blarg instance with implicit.

The above is provided in the same source file. To run the code:

Shell
$ sbt "run-main With2"
Blarg(2,asdf asdf )
Blarg(3,asdf asdf asdf )
Blarg(2,qwer qwer )
Blarg(3,qwer qwer qwer ) 

The Structural Types With Parametrics section of the Structural Types lecture extends the With Pattern by adding parametrics for type safety and uses compiler-assisted introspection to provide duck typing to ensure that resources are closed even when exceptions are thrown.

Exercise – Understanding Implicits by Reading Code

The ability to read someone else’s code is a skill that only comes with practice. What does this program do.

Scala code
import java.util.{Date, Locale}
import java.text.{NumberFormat, DateFormat}
object WithLocale extends App { def formatDateTime(date: Date)(implicit dateFormat: DateFormat): String = dateFormat.format(date)
def formatNumber(number: BigDecimal)(implicit numberFormat: NumberFormat): String = numberFormat.format(number)
def withLocale(locale: Locale)(body: Locale => String): String = body(locale)
def result(date: Date, number: BigDecimal)(implicit locale: Locale): String = { implicit val dateFormat = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, locale) implicit val numberFormat = NumberFormat.getNumberInstance(locale) val currencyCode = numberFormat.getCurrency.getCurrencyCode s"""${locale.getDisplayCountry}; currency: $currencyCode; """ + s"""date/time: ${formatDateTime(date)}; large number: ${formatNumber(number)}""" }
val resultUS = withLocale(Locale.US) { implicit locale => result(new Date, 123456789) }
val resultFrance = withLocale(Locale.FRANCE) { implicit locale => result(new Date, 987654321) }
println(resultUS) println(resultFrance) }

Solution

You can run the program like this.

Shell
$ sbt "runMain WithLocale"
United States; currency: USD; date/time: Mar 1, 2014 3:04:24 PM; large number: 123,456,789
France; currency: EUR; date/time: 1 mars 2014 15:04:24; large number: 987 654 321 

SLS §7.1

As a reminder, the syntax for Scala value implicits discussed so far can do two things.

  1. Retrieve values for method parameters from the current scope
  2. Provide values to other methods contained within the same scope

Section 7.2 of the Scala Language Specification (SLS) discusses this syntax in a formal manner. This reference is often written as SLS §7.2, because the § character means "section".

SLS §7.1 seems to discuss a lesser-known syntax for specifying implicit values to methods (I find §7.1 obtuse). I don’t like this syntax: it is not very useful and has an undesirable side effect. However, I am showing this to you because if you see this syntax you should know what you are looking at.

This syntax only supports the second capability just described: it can only implicitly provide a value within a class or method body, and it cannot receive implicit values. As usual, we will explore this by way of an example. First, some setup; you have seen similar code before. The difference with this code is the second parameter to the Sls71 class is an implicit val.

Scala code
case class Blarg(i: Int, s: String) {
  override def toString = s"$i $s"
}
class Sls71(a: Int, implicit val blarg: Blarg) { def double(implicit blarg: Blarg): Blarg = blarg.copy(i=blarg.i*2, s=blarg.s*2) def triple(implicit blarg: Blarg): Blarg = blarg.copy(i=blarg.i*3, s=blarg.s*3)
val bigBlarg = if (a<10) double else triple }

Notice that all the SLS §7.1 implicit does is simplify the method invocations for double and triple, so arguments do not need to be explicitly supplied. This syntax has the side effect of causing the implicit parameter to be a public property of the class. If you don’t want that, you could mark the property as private.

Scala code
class Sls71(a: Int, private implicit val blarg: Blarg)

Now we can use the Sls71 class in an input/eval/output loop. The Immutable Collections lecture will describe how the loop works.

Scala code
print("> ")
Iterator.continually(io.StdIn.readLine())
        .takeWhile(_ != null)
        .foreach { line =>
  try {
    val i = line.toInt
    val blarg = Blarg(i, "nom ")
    val sls71 = new Sls71(i, blarg)
    println(sls71.bigBlarg.s)
      print("> ")
  } catch {
    case ignored: Exception => sys.exit
  }
}

Here is what happened when I ran the above code. When prompted, I entered the values "3" and "13", followed by Enter. The loop terminates when the user either types Enter by itself or ^D.

Shell
$ sbt "runMain SLS7_1"
... output not shown ...
scala> 3Enter
nom nom
scala>
13Enter nom nom nom > ^D

SLS §7.1 Syntax Degrades Into §7.2 Syntax

Here is the same class constructor signature again.

Scala code
class Sls71(a: Int, implicit val blarg: Blarg)

Notice what happens if we reverse the order of the parameters:

Scala code
class Sls71(implicit val blarg: Blarg, a: Int)

This is SLS §7.2 syntax! Both parameters of the one and only parameter list are now implicit. If you do not need the Blarg parameter to be a public property of the class, the SLS §7.2 syntax does not require the val.

Scala code
class Sls71(implicit blarg: Blarg, a: Int)

* indicates a required field.

Please select the following to receive Mike Slinn’s newsletter:

You can unsubscribe at any time by clicking the link in the footer of emails.

Mike Slinn uses Mailchimp as his marketing platform. By clicking below to subscribe, you acknowledge that your information will be transferred to Mailchimp for processing. Learn more about Mailchimp’s privacy practices.