Published 2014-03-09.
Last modified 2017-06-16.
Time to read: 9 minutes.
We already know that classes and methods can accept value parameters. This lecture introduces types as a second kind of parameter for traits, classes and methods. The time
method introduced earlier is made parametric, and a DSL for C-style if-then-else syntax is developed.
Unlike value parameters, which are evaluated at runtime, type parameters are evaluated at compile time.
The sample code for this lecture can be found in
courseNotes/
.
First Look at Parametric Polymorphism
The hasValue
method takes an Option
of Int
and returns an indication of whether the Option
contains Some
value or not.
scala> def hasValue(option: Option[Int]): Boolean = option.isDefined hasValue: (option: Option[Int])Boolean
scala> hasValue(Some(3)) res0: Boolean = true
scala> hasValue(None) res1: Boolean = false
There is nothing in the definition above that is specific to integers, other than the declaration of Option
’s type.
The code for checking to see if an Option
of String
has a value is identical.
scala> def hasValue(option: Option[String]): Boolean = option.isDefined hasValue: (option: Option[String])Boolean
scala> hasValue(Some("Hi")) res2: Boolean = true
scala> hasValue(None) res3: Boolean = false
We can generalize the two definitions above by parameterizing not just the input option
but also its type.
Type parameters are enclosed within square braces and, if provided, must appear before value parameter lists.
scala> def hasValue[T](option: Option[T]): Boolean = option.isDefined hasValue: [T](option: Option[T])Boolean
Type parameters are listed in square brackets after the method name and can be used in the type declarations within the method.
In the definition above, T
is the only type parameter, standing for any Scala type.
This defines a family of hasValue
functions, one for each type
that the Scala compiler notices is used in
the program: T
hasValue[Int], hasValue[String]
, and so on.
scala> hasValue[Int](Some(1)) res4: Boolean = true
scala> hasValue[Int](None) res5: Boolean = false
Recall from the Option, Some and None lecture of the
Introduction to Scala course that
None
is a singleton object, so there is only one instance.
This means that unlike Some
, the None
instance of Option
is identical for all parametric types.
Let’s look at a few more scenarios.
scala> hasValue[String](Some("a")) res6: Boolean = true
scala> hasValue[Double](Some(123.4)) res7: Boolean = true
scala> hasValue[(String, Int)](Some(("x",2))) res8: Boolean = true
scala> hasValue[Array[Int]](Some(Array(1,2))) res9: Boolean = true
In most cases the explicit type annotation for hasValue
can be dropped because the Scala compiler will
usually be able to infer the correct parametric type automatically.
scala> hasValue(Some(1)) res10: Boolean = true
scala> hasValue(Some("a")) res11: Boolean = true
scala> hasValue(Some((1, 2))) res12: Boolean = true
scala> hasValue(Some(Array(1, 2))) res13: Boolean = true
The method hasValue
exhibits parametric polymorphism (also known as generics or templates),
which allows the method definition to represent many hasValue
methods differing only for the type of the
elements in the Option
input.
If this version of hasValue
was lifted to a Function
using eta expansion,
the equivalent function’s type would be Option[T] => Boolean
.
This means for any type T
, hasValue
takes an Option
of type T
and returns a Boolean
.
Notice that I have defined the equivalent Function
with def
, because neither a val nor a var may be parametric.
scala> def hasValue[T] = (option: Option[T]) => option.isDefined hasValue: [T]=> Option[T] => Boolean
scala> hasValue(Some(1)) res14: Boolean = true
Scoped Parameters

Classes, traits and methods can be parametric.
It is useful and accurate to think of Scala type parameters as being executed at compile time the same way as class and
method arguments are executed at runtime.
Consider the following: two classes are defined, Outer
and Inner
, each with a String
property called
propOuter
and propInner
, respectively.
case class Outer(propOuter: String) case class Inner(propInner: String)
Now we define a class, Test
, which is parametric in T
.
This means that the compiler will evaluate the value of T
at compile time and substitute values.
The value of T
is known throughout the class.
class Test[T] { def print[U](u: U, t: T): Unit = println(s"Test.test: u=$u; t=$t") }
Test also defines a method called print
which is parametric in U
.
The value for U
is local to the method.
If type values for T
and U
are not explicitly provided then the compiler will attempt to infer them.
We can now create an instance of Test
and invoke print
with the type Outer
substituted as the value of T
.
scala> new Test[Outer].print(Inner("inner"), Outer("outer")) Test.test: u=Inner(inner); t=Outer(outer)
We did not explicitly provide a type value U
, however the compiler was able to deduce that the type value must be Inner
.
Shadowed Parameters

Just as with variables and method arguments, type names can shadow each other.
As an example, consider the class Shadow
, which is parametric in T
.
Notice that this class defines a method called print
, which is also parametric in T
.
The method’s type T
is distinct from the class type T
and shadows it.
In this example, the outer T
type is defined but not used.
scala> class Shadow[T] { def print[T](t: T): Unit = println(s"Test.test: y=$t") } defined class Shadow
scala> new Shadow[Outer].print(Inner("inner")) Test.test: y=Inner(inner)
scala> new Shadow[Inner].print(Inner("inner")) Test.test: y=Inner(inner)
You can run this code by typing.
$ sbt "runMain ScopedParams" Test.test: y=Inner(inner)
Parametric Polymorphism
Here is the time
method from the previous lecture,
rewritten to use parametric types to return a strongly typed result.
We’ll define it as part of a parametric class.
class Timeable[T] { def time(block: => T): T = { val t0 = System.nanoTime() val result: T = block val elapsedMs = (System.nanoTime() - t0) / 1000000 println("Elapsed time: " + elapsedMs + "ms") result } }
The square brackets introduce a parametric type to the time
method.
In this case we only define one type, called T
.
The type could equally well have been called Result
, but it is common to use one letter names for parametric types.
Anywhere in the method that you wish to refer to that type, merely write T
.
You can invoke the method with any value of T
, and if you do not specify the value of T
it will be inferred.
In other words, if you wanted to time three methods that return an Int
, a String
and a Double
, this single
parametric method saves you from having to write the following methods, because T
is a parametric type.
def time(block: => Int): Int = ???
def time(block: => String): String = ???
def time(block: => Double): Double = ???
Let’s use this method to again time how long it takes to compute Pi
to many decimal places.
A Function1[Int, Double]
version of calculatePiFor
is provided in multi/package.scala
and could just as well
be used.
def calculatePiFor(decimalPlaces: Int): Double = { var acc = 0.0 for (i <- 0 until decimalPlaces) acc += 4.0 * (1 - (i % 2) * 2) / (2 * i + 1) acc }
Now we can run time
on calculatePiFor
.
Notice the the result is strongly typed as Double
,
instead of Any
as was the case in the
previous lecture.
scala> new Timeable.time[Double] { calculatePiFor(100000) } Elapsed time: 0ms res10: Double = 3.1415826535897198
Let’s time a function that returns a String
instead of a Double
.
scala> new Timeable.time[String] { io.Source.fromURL("https://scalacourses.com").mkString.trim } Elapsed time: 481ms res11: String = "<!DOCTYPE html> <html lang="en"> <head> <title>Welcome to ScalaCourses.com</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <script src=’/webjars/jquery/1.9.1/jquery.min.js’ type=’text/javascript’> <script src=’/webjars/jquery-ui/1.10.2/ui/minified/jquery-ui.min.js’ type=’text/javascript’> <script src=’/webjars/bootstrap/2.3.2/js/bootstrap.min.js’ type=’text/javascript’> <script src=’/webjars/bootstrap-datepicker/1.0.1/js/bootstrap-datepicker.js’ type=’text/javascript’> <script src=’/assets/javascripts/jwerty.js’ type="text/javascript"> <script src=’/javascriptRoutes’ type="text/javascript"> <link href=’/assets/images/favicon.ico’ rel="shortcut icon" type="image/x-ic...
Scala’s type inference means that we did not have to write the type parameters, so this would also work.
new Timeable.time { calculatePiFor(100000) } new Timeable.time { io.Source.fromURL("https://scalacourses.com").mkString.trim }
You can run this program by typing.
sbt "runMain TimeableT"
’With’ Pattern Revisited
We can make a parametric polymorphic version of the With pattern we learned in the More Fun With Functions lecture of the Introduction to Scala course. For such a powerful facility, it is surprising how simple and easy it is to define and use with Scala.
def withT[T, U](t: T)(operation: T => U): U = operation(t)
Now let’s use it:
scala> withT(6) { i => println(i*2) } 12
scala> withT(new java.util.Date) { println } Tue Oct 29 05:48:07 PDT 2013
scala> case class Blarg(i: Int, s: String) defined class Blarg scala> withT(Blarg(1, "hi")) { blarg => println(blarg) } Blarg(1,hi)
You can run this code example by typing:
$ sbt "runMain ParametricWith"
We will extend the With pattern in the Parametric ’With’ Pattern Revisited section of the Partial Functions lecture, and further enhance it in the Structural Types With Parametrics section of the Structural Types lecture so that it uses duck typing to manage resources.
Exercise – What is Output?
package parametricSimulation { abstract class AbstractSimulation[X, Y, Z] { def simulate(x: X, y: Y, z: Z): String }
object AbstractSimulation { implicit lazy val defaultSimulation = new AbstractSimulation[Int, Double, String] { def simulate(x: Int, y: Double, z: String) = s"Companion simulation: $x, $y, $z" } }
trait Implicit { implicit lazy val defaultSimulation = new AbstractSimulation[Int, Double, String] { def simulate(x: Int, y: Double, z: String) = s"Implicit simulation: $x, $y, $z" } }
object ParametricSimulation extends App { object CompanionSimulation { println(implicitly[AbstractSimulation[Int, Double, String]].simulate(1, 2, "three")) }
object TraitSimulation extends Implicit { println(implicitly[AbstractSimulation[Int, Double, String]].simulate(10, 20, "thirty")) }
CompanionSimulation TraitSimulation } }
Solution
Lets walk through the program.
- All of the code is contained within a
package
statement, which defines the contents of theparametricSimulation
package. - The
AbstractSimulation
abstract class is parametric in typesX
,Y
andZ
, and declares but does not define thesimulate
method, which accepts instances ofX
,Y
andZ
, and returns aString
. - The
AbstractSimulation
companion object defines animplicit lazy val
of typeAbstractSimulation
calleddefaultSimulation
. Because this implicit is defined in a companion object it has a lower priority than other implicits. Because the implicit is lazy it is not instantiated unless it is referenced. - The
Implicit
trait defines anotherimplicit lazy val
of typeAbstractSimulation
, also calleddefaultSimulation
. This is a way to define an implicit within the scope of the trait, or any type that the trait is mixed into. Mixing this trait into a class, object or trait will cause this implicit to be used instead of the implicit in theAbstractSimulation
companion object. - The console application called
ParametricSimulation
defines twoobject
s, and then evaluates them. Both of these objects have similar side effects: they obtain a reference to the activeAbstractSimulation
implicit in scope, invoke thesimulate
method, and print out the returned value.
You can run ParametricSimulation
like this.
$ sbt "runMain parametricSimulation.ParametricSimulation" Companion simulation: 1, 2.0, three Implicit simulation: 10, 20.0, thirty
Example: Ternary Operator DSL

Let’s define a DSL that provides a ternary operator similar to the ?
operator in C and C++.
The syntax we will implement is.
predicate ? thenClause | elseClause
We don’t want thenClause
to be evaluated unless the predicate evaluates true
,
and we don’t want the elseClause
to be evaluated unless the predicate evaluates false
.
Here is an example of desired usage.
util.Random.nextBoolean ? "Yes" | "No"
If we rewrite the expression using dot notation it will be easier to understand how to define the ternary operator for Scala.
util.Random.nextBoolean.?("Yes").|("No")
Our approach will be.
- Define a class called
TernaryThen
that holds the predicate. - Define a method within
TernaryThen
called?
that accepts the then clause without evaluating it and returns the evaluation result if required. - Define an inner class called
TernaryEval
within theTernaryThen
class that accepts the as-yet-not-evaluated then expression.- Define a method within
TernaryEval
called|
that the user chains fromTernaryThen
after writing the then clause and passes in the else clause. - The
|
method will evaluate the predicate and return the result of evaluating either the then clause or the else clause, as appropriate.
- Define a method within
- To trigger the DSL we will need an implicit conversion from
Boolean
(the predicate) toTernaryThen
. Any time the compiler encounters aBoolean
expression and the implicit conversion is in scope, the compiler will attempt to create an instance ofTernaryThen
. If successful, the DSL will be executed at runtime, otherwise theBoolean
expression will remain as-is. For the conversion toTernaryThen
to succeed, theBoolean
must be chained to an invocation of the?
method and the|
method.
All of the parameters should be defined as being call by name, so they are not evaluated until their value is required.
This means that neither the TernaryEval
class nor the TernaryThen
class
can be defined as value objects.
Here is the code. Even though it is short, there is a lot going on.
class TernaryThen(predicate: => Boolean) { import scala.language.implicitConversions
def ?[A](thenClause: => A) = new TernaryEval(thenClause)
class TernaryEval[A](thenClause: => A) { def |(elseClause: => A): A = if (predicate) thenClause else elseClause } }
implicit def toTernaryThen(predicate: => Boolean): TernaryThen = new TernaryThen(predicate)
This code is worthy of further explanation.
- The
toTernaryThen
implicit conversion attempts to convert all instances ofBoolean
toTernaryThen
. - The
TernaryThen
?
method acceptsthenClause
without evaluating it.TernaryThen
’s?
method is parametric inA
, which is the method’s return type. Note thatA
’s scope is limited to the?
method because the compiler can only infer the type of the then clause when it parses the expression. The key to understanding this is to realize that the Scala compiler builds an abstract syntax tree (AST) when it parses an expression; the AST can then optionally evaluate the expression at runtime if required. Once the compiler builds the AST, the type of the expression is known at compile time even though the expression has not yet been evaluated at runtime. - The
?
method creates an instance of an inner class calledTernaryEval
and passes in thethenClause
reference, which still has not been evaluated. - The
TernaryEval
inner class is parametric inA
, and accepts the reference to the then clause, and defines the|
method. The then clause returns an instance ofA
. Note that A’s scope is limited toTernaryEval
. Although thisA
is distinct from the?
method’s return type (which is also calledA
) bothA
types will be the same because they are both defined to be the result of evaluatingthenClause
. - The | method accepts the
elseClause
parameter without evaluating it and returns an instance ofA
. - The | method finally evaluates
predicate
, and returns the result of evaluatingthenClause
orelseClause
. The result is of typeA
, and eachA
must resolve to the same type.
Let’s try it.
scala> util.Random.nextBoolean ? "Yes" | "No"
res6: String = Yes
This usage example shows how the type of the else clause must match the type of the then clause.
This works because Predef
provides an implicit conversion from Int
to Double
.
scala> util.Random.nextBoolean ? 1.0 | 99
res5: Double = 1.0
Since there is no implicit conversion of Double
to Int
, this fails.
scala> util.Random.nextBoolean ? 1 | 99.0
<console>:14: error: type mismatch;
found : Double(99.0)
required: Int
util.Random.nextBoolean ? 1 | 99.0
^
You can run this code by typing.
$ sbt "runMain Ternary1" util.Random.nextBoolean ? "Yes" | "No" = No
Another implementation
Here is an implementation that uses anonymous classes.
implicit def toTernaryThenAC(predicate: Boolean) = new { def ?[A](thenClause: => A) = new { def |(elseClause: => A) = if (predicate) thenClause else elseClause } }
Let’s try it.
scala> util.Random.nextBoolean ? "Yes" | "No"
res8: String = Yes
The anonymous class implementation defines two new classes each time the Scala compiler resolves the implicit conversion.
It is therefore better to use the TernaryThen
implementation.
You can run this code by typing.
$ sbt "runMain Ternary2" util.Random.nextBoolean ? "Yes" | "No" = No
Parametric Traits as Rich Interfaces
This pattern is useful to enhance existing Scala and Java classes. It is an alternative to the Enrich My Library pattern introduced in the Implicit Classes lecture. This approach has the advantage of not introducing implicits, which can be hard to debug. Take a moment and study this trait.
trait RichIterable[A] { def iterator: java.util.Iterator[A]
def foreach(f: A => Unit): Unit = { val iter = iterator while (iter.hasNext) f(iter.next) }
def foldLeft(seed: A)(f: (A, A) => A): A = { var result = seed foreach { item => result = f(result, item) } result } }
As you can see, the iterator
method is abstract.
In other words, iterator
is declared but not defined.
Concrete subclasses of the RichIterable
trait must implement the iterator
method.
Does this statement in the foreach
method seem odd.
val iter = iterator
This statement captures the result of the iterator
method and stores it in the locally scoped variable called iter
.
This is done because iterators are often fragile.
Saving the result of a method call that returns an iterator is good defensive programming.
Now let’s consider how to use the RichIterable
trait.
Remember the declaration of iter
is
java.util.Iterator[A]
.
If you examine the Javadoc for java.util.HashSe
t, you will see that it already defines a method called
iterator
that returns a
java.util.Iterator<A>
(that was written in Java - you would write it in Scala as java.util.Iterator[A]
).
Consider the following anonymous class.
java.util.HashSet[Int] with RichIterable[Int]
The resulting anonymouis class is concrete because the superclass (HashSet
) provides an implementation for the abstract
RichInterable
trait’s undefined iterator
method.
An instance could be created by writing.
val richSet = new java.util.HashSet[Int] with RichIterable[Int]
Let’s use RichIterable
to add Scala functionality to an anonymous subclass of java.util.HashSet
, like this.
scala> val richSet = new java.util.HashSet[Int] with RichIterable[Int] richSet: java.util.HashSet[Int] with RichIterable[Int] = []
scala> richSet.add(1) res13: Boolean = true
scala> richSet.add(2) res14: Boolean = true
scala> richSet.add(2) res15: Boolean = true
scala> val total = richSet.foldLeft(0)(_ + _) total: Int = 6
scala> s"richSet = ${richSet.toArray.mkString(", ")}; total = $total" richSet = 1, 2, 3; total = 6
To run this program, type.
$ sbt "runMain RichInterface"
@implicitAmbiguous
Scala 2.12 introduced the @implicitAmbiguous
annotation, which can only be applied to implicit methods that accept type parameters.
From the Scala 2.12-M3 release notes.
The
@implicitAmbiguous
annotation allows customizing the error message when an implicit search finds multiple ambiguous values. Refer to the Scaladoc of the annotation class for an example.
The code example in the Scaladoc is rather crazy. Here is a simpler example.
scala> case class X[C, D](c: C, d: D) defined class X
scala> @annotation.implicitAmbiguous("ambig1 problem: X[${J}, ${J}]") implicit def ambig1[J](j: J): X[J, J] = X(j, j) ambig1: [J](j: J)X[J,J]
scala> @annotation.implicitAmbiguous("ambig2 problem: X[${J}, ${J}]") implicit def ambig2[J](j: J): X[J, J] = X(j, j) ambig2: [J](j: J)X[J,J]
scala> val x12: X[Int, Int] = 1 <console>:15: error: ambig1 problem: X[Int, Int] val x12: X[Int, Int] = 1 ^
Parameters with Abstract Classes vs Traits
You can define a trait with parameters.
trait Blah[X, Y] { /* ... */ }
And you can define an abstract class with parameters.
abstract class Blah[X, Y] { /* ... */ }
I generally recommend using abstract classes with parameters instead of traits with abstract members that must be overriden by implementing classes. Abstract classes usually works better with type inference, because subclasses do not infer their type arguments or the types of their methods from methods of superclasses, but subclasses do infer the their type arguments from their parameters, which superclasses can pass in.
© 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.