4. Are you interested?
● Covers some of the harder Scala concepts
● Predef and package objects
● Types, Abstract Types & Type Projections
● implicit Parameters, Converters, Wrappers
● Manifests
● Type Variances and Bounds
● Other goodness
6. Predef
● scala.Predef object
● Automatically available since scala package is
automatically included.
● Contains commons type aliases, and implicits
(to be discussed)
9. Types
class Foo {
class Bar {}
}
val foo = new Foo()
val bar = new foo.Bar()
10. Types
class Foo {
class Bar {}
}
val foo = new Foo()
val bar = new foo.Bar()
* As opposed to Java, Inner objects belong to the
Outer Object not the outer class
11. Types
class Foo {
class Bar {}
}
val foo = new Foo()
val bar:Foo#Bar = new foo.Bar()
val bar:foo.Bar = new foo.Bar()
12. Types
class Foo {
class Bar {}
}
val foo = new Foo()
val bar:Foo#Bar = new foo.Bar()
val bar:foo.Bar = new foo.Bar()
13. Types
class Foo {
class Bar {}
}
val foo = new Foo()
val bar:Foo#Bar = new foo.Bar()
val bar:foo.Bar = new foo.Bar()
14. Types
class Foo {
class Bar {}
}
val foo = new Foo()
val bar:Foo#Bar = new foo.Bar()
val bar:foo.Bar = new foo.Bar()
23. Stable/Singleton Type
case class Celebrity(firstName:String,
lastName:String)
val tomHanks = new Celebrity("Tom", "Hanks")
val jodieFoster = new Celebrity("Jodie",
"Foster")
val tomHanksImposter =
new Celebrity("Tom", "Hanks")
def enterTomHanksHouse(x:tomHanks.type) {}
24. Stable/Singleton Type
class Celebrity(firstName:String,
lastName:String)
val tomHanks = new Celebrity("Tom", "Hanks")
val jodieFoster = Celebrity("Jodie", "Foster")
val tomHanksImposter =
new Celebrity("Tom", "Hanks")
def enterTomHanksHouse(x:tomHanks.type) {}
25. Stable/Singleton Type
class Celebrity(firstName:String,
lastName:String)
val tomHanks = new Celebrity("Tom", "Hanks")
val jodieFoster = Celebrity("Jodie", "Foster")
val tomHanksImposter =
new Celebrity("Tom", "Hanks")
def enterTomHanksHouse(x:tomHanks.type) {}
enterTomHanksHouse(tomHanks) //OK
26. Stable/Singleton Type
class Celebrity(firstName:String,
lastName:String)
val tomHanks = new Celebrity("Tom", "Hanks")
val jodieFoster = Celebrity("Jodie", "Foster")
val tomHanksImposter =
new Celebrity("Tom", "Hanks")
def enterTomHanksHouse(x:tomHanks.type) {}
enterTomHanksHouse(tomHanks) //OK
enterTomHanksHouse(jodieFoster) //Wrong
27. Stable/Singleton Type
class Celebrity(firstName:String,
lastName:String)
val tomHanks = new Celebrity("Tom", "Hanks")
val jodieFoster = Celebrity("Jodie", "Foster")
val tomHanksImposter =
new Celebrity("Tom", "Hanks")
def enterTomHanksHouse(x:tomHanks.type) {}
enterTomHanksHouse(tomHanks) //OK
enterTomHanksHouse(jodieFoster) //Wrong
enterTomHanksHouse(tomHanksImposter) //Wrong
28. Abstract Types
abstract class Generator {
type F
def generate: F
}
class StringGenerator extends Generator {
type F = String
def generate = "Scooters are fun"
}
new StringGenerator().generate // Scooters are fun
29. Abstract Types
abstract class Generator {
type F
def generate: F
}
class StringGenerator extends Generator {
type F = String
def generate = "Scooters are fun"
}
new StringGenerator().generate // Scooters are fun
30. Abstract Types
abstract class Generator {
type F
def generate: F
}
class StringGenerator extends Generator {
type F = String
def generate = "Scooters are fun"
}
new StringGenerator().generate // Scooters are fun
31. Abstract Types
abstract class Generator {
type F
def generate: F
}
class StringGenerator extends Generator {
type F = String
def generate = "Scooters are fun"
}
new StringGenerator().generate // Scooters are fun
32. Abstract Types
abstract class Generator {
type F
def generate: F
}
class StringGenerator extends Generator {
type F = String
def generate = "Scooters are fun"
}
val x = new StringGenerator()
classOf[x.F] = class java.lang.String
classOf[x.type#F] = class java.lang.String
classOf[StringGenerator#F] = class java.lang.String
33. Abstract Types
abstract class Generator {
type F
def generate: F
}
class StringGenerator extends Generator {
type F = String
def generate = "Scooters are fun"
}
val x = new StringGenerator()
classOf[x.F] = class java.lang.String
classOf[x.type#F] = class java.lang.String
classOf[StringGenerator#F] = class java.lang.String
val w:x.F = “Oh yeah!”
val x:x.type#F = “Rock and Roll”
36. Infix Types
case class Person(name: String)
class Loves[A, B](val a: A, val b: B)
def announceCouple
(couple: Loves[Person, Person]) = {
couple.a.name + " is in love with " +
couple.b.name
}
val romeo = new Person("Romeo")
val juliet = new Person("Juliet")
announceCouple(new Loves(romeo, juliet))
//Romeo is in love with Juliet")
37. Infix Types
case class Person(name: String)
class Loves[A, B](val a: A, val b: B)
def announceCouple
(couple: Loves[Person, Person]) = {
couple.a.name + " is in love with " +
couple.b.name
}
val romeo = new Person("Romeo")
val juliet = new Person("Juliet")
announceCouple(new Loves(romeo, juliet))
//Romeo is in love with Juliet")
38. Infix Types
case class Person(name: String)
class Loves[A, B](val a: A, val b: B)
def announceCouple
(couple: Loves[Person, Person]) = {
couple.a.name + " is in love with " +
couple.b.name
}
val romeo = new Person("Romeo")
val juliet = new Person("Juliet")
announceCouple(new Loves(romeo, juliet))
//Romeo is in love with Juliet")
39. Infix Types
case class Person(name: String)
class Loves[A, B](val a: A, val b: B)
def announceCouple
(couple: Person Loves Person) = {
couple.a.name + " is in love with " +
couple.b.name
}
val romeo = new Person("Romeo")
val juliet = new Person("Juliet")
announceCouple(new Loves(romeo, juliet))
//Romeo is in love with Juliet")
40. Infix Types
case class Person(name: String)
class Loves[A, B](val a: A, val b: B)
def announceCouple
(couple: Person Loves Person) = {
couple.a.name + " is in love with " +
couple.b.name
}
val romeo = new Person("Romeo")
val juliet = new Person("Juliet")
announceCouple(new Loves(romeo, juliet))
//Romeo is in love with Juliet
*It would be nice to say “romeo loves juliet”
41. Infix Types with Infix Operators
case class Person(name: String) {
def loves(person: Person) =
new Loves(this, person)
}
class Loves[A, B](val a: A, val b: B)
def announceCouple(couple: Person Loves Person) =
{
couple.a.name + " is in love with " +
couple.b.name
}
val romeo = new Person("Romeo")
val juliet = new Person("Juliet")
announceCouple(romeo loves juliet)
//Romeo is in love with Juliet")
42. Infix Types with Infix Operators
case class Person(name: String) {
def loves(person: Person) =
new Loves(this, person)
}
class Loves[A, B](val a: A, val b: B)
def announceCouple(couple: Person Loves Person) =
{
couple.a.name + " is in love with " +
couple.b.name
}
val romeo = new Person("Romeo")
val juliet = new Person("Juliet")
announceCouple(romeo loves juliet)
//Romeo is in love with Juliet")
43. Infix Types with Infix Operators
case class Person(name: String) {
def loves(person: Person) =
new Loves(this, person)
}
class Loves[A, B](val a: A, val b: B)
def announceCouple(couple: Person Loves Person) =
{
couple.a.name + " is in love with " +
couple.b.name
}
val romeo = new Person("Romeo")
val juliet = new Person("Juliet")
announceCouple(romeo loves juliet)
//Romeo is in loveyou can omitJuliet param methods
*Scala is a loose syntax language, with the () for one
49. implicit parameters
def howMuchCanIMake_?(hours: Int)(implicit
dollarsPerHour: BigDecimal) =
dollarsPerHour * hours
implicit var hourlyRate = BigDecimal(34.00)
*implicit reference must be in scope to be satisfied
66. implicit objects in implicit
parameters
case class Employee(firstName:String, lastName:String,
salary:Float)
67. implicit objects in implicit
parameters
case class Employee(firstName:String, lastName:String,
salary:Float)
implicit object CEO extends Employee("Charo",
"Frostycorn",
499000.22f)
68. implicit objects in implicit
parameters
case class Employee(firstName:String, lastName:String,
salary:Float)
implicit object CEO extends Employee("Charo",
"Frostycorn",
499000.22f)
def isEmployeePaidTooMuch_?(salary:Float)(implicit
modelEmployee:Employee) = salary > modelEmployee.salary
* Using floating point as currency used for demonstration purposes only.
70. Monkey Patching in Ruby
class Integer
def squared
self * self
end
end
>> 4.squared
=> 16
Source: http://paulbarry.com/articles/2009/04/17/implicit-conversions-scalas-type-safe-answer-to-rubys-open-class
71. Issues with Monkey Patching in
Ruby
● Other imports can override the your
patch, effectively making
debugging difficult.
● There are other ways of achieving
the same effect. http://bit.ly/RBid2D
Source:http://www.rubyinside.com/the-end-of-monkeypatching-4570.html
79. implicit wrappers
class MyIntWrapper(val original: Int) {
def isOdd = original % 2 != 0
}
implicit def int2MyIntWrapper(value: Int) = new
MyIntWrapper(value)
* The implicit needs to be within the same scope it is to be used
80. implicit wrappers
class MyIntWrapper(val original: Int) {
def isOdd = original % 2 != 0
}
implicit def int2MyIntWrapper(value: Int) = new
MyIntWrapper(value)
19.isOdd // true
20.isOdd // false
116. Manifests
def inspect[T](l: List[T])
(implicit manifest:Manifest[T])
= manifest.toString
val list = 1 :: 2 :: 3 :: 4 :: 5 :: Nil
inspect(list) // Int
117. Manifests
def inspect[T](l: List[T])
(implicit manifest:Manifest[T])
= manifest.toString
val list = 1 :: 2 :: 3 :: 4 :: 5 :: Nil
inspect(list) // Int
118. Manifests
def inspect[T](l: List[T])
(implicit manifest:Manifest[T])
= manifest.toString
val list = 1 :: 2 :: 3 :: 4 :: 5 :: Nil
inspect(list) // Int
119. Manifests
case class Monkey(name: String)
class Barrel[T](implicit m:scala.reflect.Manifest[T]{
def +(t: T) = "1 %s has been
added".format(m.erasure.getSimpleName)
}
val monkeyBarrel = new Barrel[Monkey]
monkeyBarrel + new Monkey("Shotgun")
// "1 Monkey has been added"
120. Manifests
case class Monkey(name: String)
class Barrel[T](implicit m:scala.reflect.Manifest[T]{
def +(t: T) = "1 %s has been
added".format(m.erasure.getSimpleName)
}
val monkeyBarrel = new Barrel[Monkey]
monkeyBarrel + new Monkey("Shotgun")
// "1 Monkey has been added"
121. Manifests
case class Monkey(name: String)
class Barrel[T](implicit m:scala.reflect.Manifest[T]){
def +(t: T) = "1 %s has been
added".format(m.erasure.getSimpleName)
}
val monkeyBarrel = new Barrel[Monkey]
monkeyBarrel + new Monkey("Shotgun")
// "1 Monkey has been added"
122. Manifests
case class Monkey(name: String)
class Barrel[T](implicit m:scala.reflect.Manifest[T]){
def +(t: T) = "1 %s has been
added".format(m.erasure.getSimpleName)
}
val monkeyBarrel = new Barrel[Monkey]
monkeyBarrel + new Monkey("Shotgun")
// "1 Monkey has been added"
123. Manifests
case class Monkey(name: String)
class Barrel[T](implicit m:scala.reflect.Manifest[T]{
def +(t: T) = "1 %s has been
added".format(m.erasure.getSimpleName)
}
val monkeyBarrel = new Barrel[Monkey]
monkeyBarrel + new Monkey("Shotgun")
// "1 Monkey has been added"
124. Manifests
case class Monkey(name: String)
class Barrel[T](implicit m:scala.reflect.Manifest[T]{
def +(t: T) = "1 %s has been
added".format(m.erasure.getSimpleName)
}
val monkeyBarrel = new Barrel[Monkey]
monkeyBarrel + new Monkey("Shotgun")
// "1 Monkey has been added"
125. Manifests
case class Monkey(name: String)
class Barrel[T](implicit m:scala.reflect.Manifest[T]{
def +(t: T) = "1 %s has been
added".format(m.erasure.getSimpleName)
}
val monkeyBarrel = new Barrel[Monkey]
monkeyBarrel + new Monkey("Shotgun")
// "1 Monkey has been added"
126. Manifests
case class Monkey(name: String)
class Barrel[T](implicit m:scala.reflect.Manifest[T]{
def +(t: T) = "1 %s has been
added".format(m.erasure.getSimpleName)
}
val monkeyBarrel = new Barrel[Monkey]
monkeyBarrel + new Monkey("Shotgun")
// "1 Monkey has been added"
129. The Setup
trait Fruit
abstract class Citrus extends Fruit
class Orange extends Citrus
class Tangelo extends Citrus
class Apple extends Fruit
class Banana extends Fruit
class NavelOrange extends Fruit
130. Simple Invariant Case
class MyContainer[A](a: A)
(implicit manifest:
scala.reflect.Manifest[A]) {
private[this] var item = a
def get = item
def set(a: A) {item = a}
def contents =
manifest.erasure.getSimpleName
}
val fruitBasket = new MyContainer(new Orange())
fruitBasket.contents // Orange
131. Simple Invariant Case
class MyContainer[A](a: A)
(implicit manifest:
scala.reflect.Manifest[A]) {
private[this] var item = a
def get = item
def set(a: A) {item = a}
def contents =
manifest.erasure.getSimpleName
}
val fruitBasket = new MyContainer(new Orange())
fruitBasket.contents // Orange
132. Simple Invariant Case
class MyContainer[A](a: A)
(implicit manifest:
scala.reflect.Manifest[A]) {
private[this] var item = a
def get = item
def set(a: A) {item = a}
def contents =
manifest.erasure.getSimpleName
}
val fruitBasket = new MyContainer(new Orange())
fruitBasket.contents // Orange
133. Simple Invariant Case
class MyContainer[A](a: A)
(implicit manifest:
scala.reflect.Manifest[A]) {
private[this] var item = a
def get = item
def set(a: A) {item = a}
def contents =
manifest.erasure.getSimpleName
}
val fruitBasket = new MyContainer(new Orange())
fruitBasket.contents // Orange
134. Explicitly Declaring Type
class MyContainer[A](a: A)
(implicit manifest:
scala.reflect.Manifest[A]) {
private[this] var item = a
def get = item
def set(a: A) {item = a}
def contents = manifest.erasure.getSimpleName
}
val fruitBasket = new MyContainer[Fruit]
(new Orange()) //Explicit call
fruitBasket.contents // Fruit - static type
135. Explicitly Declaring Type
class MyContainer[A](a: A)
(implicit manifest:
scala.reflect.Manifest[A]) {
private[this] var item = a
def get = item
def set(a: A) {item = a}
def contents = manifest.erasure.getSimpleName
}
val fruitBasket = new MyContainer[Fruit]
(new Orange()) //Explicit call
fruitBasket.contents // Fruit - static type
136. Explicitly Declaring Type Differently
class MyContainer[A](a: A)
(implicit manifest:
scala.reflect.Manifest[A]) {
private[this] var item = a
def get = item
def set(a: A) {item = a}
def contents =
manifest.erasure.getSimpleName
}
val fruitBasket = new MyContainer(new
Orange():Fruit) //Explicit call
fruitBasket.contents // "Fruit" - static type
137. Explicitly Declaring Type Differently
class MyContainer[A](a: A)
(implicit manifest:
scala.reflect.Manifest[A]) {
private[this] var item = a
def get = item
def set(a: A) {item = a}
def contents =
manifest.erasure.getSimpleName
}
val fruitBasket = new MyContainer(new
Orange():Fruit) //Explicit call
fruitBasket.contents // "Fruit" - static type
138. Explicitly Type Coersion
class MyContainer[A](a: A)
(implicit manifest:
scala.reflect.Manifest[A]) {
private[this] var item = a
def get = item
def set(a: A) {item = a}
def contents = manifest.erasure.getSimpleName
}
val fruitBasket: MyContainer[Fruit] = new
MyContainer(new Orange())//Coerced
fruitBasket.contents // "Fruit"
139. Explicitly Type Coersion
class MyContainer[A](a: A)
(implicit manifest:
scala.reflect.Manifest[A]) {
private[this] var item = a
def get = item
def set(a: A) {item = a}
def contents = manifest.erasure.getSimpleName
}
val fruitBasket: MyContainer[Fruit] = new
MyContainer(new Orange())//Coerced
fruitBasket.contents // "Fruit"
140. Explicitly Type Coersion
class MyContainer[A](a: A)
(implicit manifest:
scala.reflect.Manifest[A]) {
private[this] var item = a
def get = item
def set(a: A) {item = a}
def contents = manifest.erasure.getSimpleName
}
val fruitBasket: MyContainer[Fruit] = new
MyContainer(new Orange())//Coerced
fruitBasket.contents // "Fruit"
*Based on the expected type it fills it in with type inference
141. Attempting Polymorphism
class MyContainer[A](a: A)
(implicit manifest:
scala.reflect.Manifest[A]) {
private[this] var item = a
def get = item
def set(a: A) {item = a}
def contents = manifest.erasure.getSimpleName
}
val fruitBasket:MyContainer[Fruit] = new
MyContainer[Orange](new Orange())
142. Attempting Polymorphism
class MyContainer[A](a: A)
(implicit manifest:
scala.reflect.Manifest[A]) {
private[this] var item = a
def get = item
def set(a: A) {item = a}
def contents = manifest.erasure.getSimpleName
}
val fruitBasket:MyContainer[Fruit] = new
MyContainer[Orange](new Orange())
[error] type mismatch;
[error] found : MyContainer[Orange]
[error] required: MyContainer[Fruit]
144. Covariance
class MyContainer[+A](a: A)
(implicit manifest:
scala.reflect.Manifest[A]) {
private[this] val item = a
def get = item
def contents = manifest.erasure.getSimpleName
}
val fruitBasket: MyContainer[Fruit] = new
MyContainer[Orange](new Orange())
fruitBasket.contents // Orange
145. Covariance
class MyContainer[+A](a: A)
(implicit manifest:
scala.reflect.Manifest[A]) {
private[this] val item = a
def get = item
def contents = manifest.erasure.getSimpleName
}
val fruitBasket: MyContainer[Fruit] = new
MyContainer[Orange](new Orange())
fruitBasket.contents // Orange
146. Covariance
class MyContainer[+A](a: A)
(implicit manifest:
scala.reflect.Manifest[A]) {
private[this] val item = a
def get = item
def contents = manifest.erasure.getSimpleName
}
val fruitBasket: MyContainer[Fruit] = new
MyContainer[Orange](new Orange())
fruitBasket.contents // Orange
*There is something missing
*No Method Parameters
147. Covariance
class MyContainer[+A](a: A)
(implicit manifest:
scala.reflect.Manifest[A]) {
private[this] val item = a
def get = item
def contents = manifest.erasure.getSimpleName
}
class NavelOrange extends Orange
val navelOrangeBasket: MyContainer[NavelOrange] =
new MyContainer[Orange](new Orange()) //Bad!
val tangeloBasket: MyContainer[Tangelo] = new
MyContainer[Orange](new Orange()) //Bad!
148. Covariance
class MyContainer[+A](a: A)
(implicit manifest:
scala.reflect.Manifest[A]) {
private[this] val item = a
def get = item
def contents = manifest.erasure.getSimpleName
}
class NavelOrange extends Orange
val navelOrangeBasket: MyContainer[NavelOrange] =
new MyContainer[Orange](new Orange()) //Bad!
val tangeloBasket: MyContainer[Tangelo] = new
MyContainer[Orange](new Orange()) //Bad!
149. Covariance
class MyContainer[+A](a: A)
(implicit manifest:
scala.reflect.Manifest[A]) {
private[this] val item = a
def get = item
def contents = manifest.erasure.getSimpleName
}
class NavelOrange extends Orange
val navelOrangeBasket: MyContainer[NavelOrange] =
new MyContainer[Orange](new Orange()) //Bad!
val tangeloBasket: MyContainer[Tangelo] = new
MyContainer[Orange](new Orange()) //Bad!
150. Covariance
class MyContainer[+A](a: A)
(implicit manifest:
scala.reflect.Manifest[A]) {
private[this] val item = a
def get = item
def contents = manifest.erasure.getSimpleName
}
class NavelOrange extends Orange
val navelOrangeBasket: MyContainer[NavelOrange] =
new MyContainer[Orange](new Orange()) //Bad!
val tangeloBasket: MyContainer[Tangelo] = new
MyContainer[Orange](new Orange()) //Bad!
151. Covariance Explained
trait Fruit
abstract class Citrus extends Fruit
class Orange extends Citrus
class Tangelo extends Citrus
class Apple extends Fruit
class Banana extends Fruit
class NavelOrange extends Orange
I have an Orange Basket, you have a Fruit Basket
153. Contravariance
class MyContainer[-A](a: A)
(implicit manifest:
scala.reflect.Manifest[A]) {
private[this] var item = a
def set(a: A) {item = a}
def contents = manifest.erasure.getSimpleName
}
154. Contravariance
class MyContainer[-A](a: A)
(implicit manifest:
scala.reflect.Manifest[A]) {
private[this] var item = a
def set(a: A) {item = a}
def contents = manifest.erasure.getSimpleName
}
155. Contravariance
class MyContainer[-A](a: A)
(implicit manifest:
scala.reflect.Manifest[A]) {
private[this] var item = a
def set(a: A) {item = a}
def contents = manifest.erasure.getSimpleName
}
156. Contravariance
class MyContainer[-A](a: A)
(implicit manifest:
scala.reflect.Manifest[A]) {
private[this] var item = a
def set(a: A) {item = a}
def contents = manifest.erasure.getSimpleName
}
val citrusBasket: MyContainer[Citrus] = new
MyContainer[Citrus](new Orange)
citrusBasket.contents // Citrus
157. Contravariance
class MyContainer[-A](a: A)
(implicit manifest:
scala.reflect.Manifest[A]) {
private[this] var item = a
def set(a: A) {item = a}
def contents = manifest.erasure.getSimpleName
}
val citrusBasket: MyContainer[Citrus] = new
MyContainer[Citrus](new Orange)
citrusBasket.contents // Citrus
158. Contravariance
class MyContainer[-A](a: A)
(implicit manifest:
scala.reflect.Manifest[A]) {
private[this] var item = a
def set(a: A) {item = a}
def contents = manifest.erasure.getSimpleName
}
*There is something missing
*No Return Values
159. Contravariance
class MyContainer[-A](a: A)
(implicit manifest:
scala.reflect.Manifest[A]) {
private[this] var item = a
def set(a: A) {item = a}
def contents = manifest.erasure.getSimpleName
}
val citrusBasket: MyContainer[Citrus] = new
MyContainer[Citrus](new Orange)
citrusBasket.contents // Citrus
160. Contravariance
class MyContainer[-A](a: A)
(implicit manifest:
scala.reflect.Manifest[A]) {
private[this] var item = a
def set(a: A) {item = a}
def contents = manifest.erasure.getSimpleName
}
val orangeBasket: MyContainer[Orange] = new
MyContainer[Citrus](new Tangelo)
orangeBasket.contents // Citrus
161. Contravariance
class MyContainer[-A](a: A)
(implicit manifest:
scala.reflect.Manifest[A]) {
private[this] var item = a
def set(a: A) {item = a}
def contents = manifest.erasure.getSimpleName
}
val tangeloBasket: MyContainer[Tangelo] = new
MyContainer[Citrus](new Orange)
tangeloBasket.contents // Citrus
162. Contravariance
class MyContainer[-A](a: A)
(implicit manifest:
scala.reflect.Manifest[A]) {
private[this] var item = a
def set(a: A) {item = a}
def contents = manifest.erasure.getSimpleName
}
val fruitBasket: MyContainer[Fruit] = new
MyContainer[Orange](new Orange())
type mismatch;
[error] found : MyContainer[Orange]
[error] required: MyContainer[Fruit]
163. Contravariance
class MyContainer[-A](a: A)
(implicit manifest:
scala.reflect.Manifest[A]) {
private[this] var item = a
def set(a: A) {item = a}
def contents = manifest.erasure.getSimpleName
}
val fruitBasket: MyContainer[Fruit] = new
MyContainer(new Orange())
*This is ok! Why?
164. Contravariance Explained
trait Fruit
abstract class Citrus extends Fruit
class Orange extends Citrus
class Tangelo extends Citrus
class Apple extends Fruit
class Banana extends Fruit
class NavelOrange extends Orange
I have an Orange Basket, you have a NavelOrange Basket
165. Invariance Revisited
class MyContainer[A](a: A)
(implicit manifest:
scala.reflect.Manifest[A]) {
private[this] var item = a
def set(a: A) {item = a}
def get = item
def contents = manifest.erasure.getSimpleName
}
val citrusBasket: MyContainer[Citrus] = new
MyContainer[Citrus](new Orange)
citrusBasket.set(new Orange)
citrusBasket.contents // Citrus
citrusBasket.set(new Tangelo)
citrusBasket.contents // Citrus
166. Invariance Revisited
class MyContainer[A](a: A)
(implicit manifest:
scala.reflect.Manifest[A]) {
private[this] var item = a
def set(a: A) {item = a}
def get = item
def contents = manifest.erasure.getSimpleName
}
val citrusBasket: MyContainer[Citrus] = new
MyContainer[Citrus](new Orange)
citrusBasket.set(new Orange)
citrusBasket.contents // Citrus
citrusBasket.set(new Tangelo)
citrusBasket.contents // Citrus
167. Invariance Revisited
class MyContainer[A](a: A)
(implicit manifest:
scala.reflect.Manifest[A]) {
private[this] var item = a
def set(a: A) {item = a}
def get = item
def contents = manifest.erasure.getSimpleName
}
val citrusBasket: MyContainer[Citrus] = new
MyContainer[Citrus](new Orange)
citrusBasket.set(new Orange)
citrusBasket.contents // Citrus
citrusBasket.set(new Tangelo)
citrusBasket.contents // Citrus
168. Real Life Scala Funk
abstract class Funny[+A, +B] {
def foo(a:A):B
}
[error] covariant type A occurs in contravariant
position in type A of value a
[error] def foo(a:A):B
[error] ^
[error] one error found
*Method Parameter is in the contravariant position
*Return Value is in the covariant position
169. Real Life Scala Funk (Fixed)
abstract class Funny[-A, +B] {
def foo(a:A):B
}
Mind Trick: - goes in ; + goes out
171. Type Bounds
● Constrain what can be used in a class
● Constrain what can be used in a type
● They are orthogonal to type variance
● Scala Only
172. Upper Bound
class MyContainer[A <: Citrus](a: A)
(implicit manifest:
scala.reflect.Manifest[A]) {
private[this] var item = a
def set(a: A) {item = a}
def get = item
def contents = manifest.erasure.getSimpleName
}
173. Upper Bound
class MyContainer[A <: Citrus](a: A)
(implicit manifest:
scala.reflect.Manifest[A]) {
private[this] var item = a
def set(a: A) {item = a}
def get = item
def contents = manifest.erasure.getSimpleName
}
174. Upper Bound
class MyContainer[A <: Citrus](a: A)
(implicit manifest:
scala.reflect.Manifest[A]) {
private[this] var item = a
def set(a: A) {item = a}
def get = item
def contents = manifest.erasure.getSimpleName
}
val citrusBasket: MyContainer[Citrus] = new
MyContainer[Citrus](new Orange)
citrusBasket.set(new Orange)
citrusBasket.contents // Citrus
175. Upper Bound
class MyContainer[A <: Citrus](a: A)
(implicit manifest:
scala.reflect.Manifest[A]) {
private[this] var item = a
def set(a: A) {item = a}
def get = item
def contents = manifest.erasure.getSimpleName
}
val citrusBasket: MyContainer[Citrus] = new
MyContainer[Citrus](new Orange)
citrusBasket.set(new Orange)
citrusBasket.contents // Citrus
176. Upper Bound
class MyContainer[A <: Citrus](a: A)
(implicit manifest:
scala.reflect.Manifest[A]) {
private[this] var item = a
def set(a: A) {item = a}
def get = item
def contents = manifest.erasure.getSimpleName
}
val citrusBasket: MyContainer[Citrus] = new
MyContainer[Citrus](new Orange)
citrusBasket.set(new Orange)
citrusBasket.contents // Citrus
177. Upper Bound
class MyContainer[A <: Citrus](a: A)
(implicit manifest:
scala.reflect.Manifest[A]) {
private[this] var item = a
def set(a: A) {item = a}
def get = item
def contents = manifest.erasure.getSimpleName
}
val citrusBasket: MyContainer[Citrus] = new
MyContainer[Citrus](new Orange)
citrusBasket.set(new Orange)
citrusBasket.contents // Citrus
178. Upper Bound
class MyContainer[A <: Citrus](a: A)
(implicit manifest:
scala.reflect.Manifest[A]) {
private[this] var item = a
def set(a: A) {item = a}
def get = item
def contents = manifest.erasure.getSimpleName
}
val citrusBasket: MyContainer[Citrus] = new
MyContainer[Citrus](new Orange)
citrusBasket.set(new Orange)
citrusBasket.contents // Citrus
citrusBasket.set(new Tangelo)
citrusBasket.contents // Citrus
179. Upper Bound
class MyContainer[A <: Citrus](a: A)
(implicit manifest:
scala.reflect.Manifest[A]) {
private[this] var item = a
def set(a: A) {item = a}
def get = item
def contents = manifest.erasure.getSimpleName
}
new MyContainer(new Orange) //OK
180. Upper Bound
class MyContainer[A <: Citrus](a: A)
(implicit manifest:
scala.reflect.Manifest[A]) {
private[this] var item = a
def set(a: A) {item = a}
def get = item
def contents = manifest.erasure.getSimpleName
}
new MyContainer(new Orange) //OK
new MyContainer[Fruit](new Orange)
type arguments [Fruit] do not conform to class
MyContainer's type parameter bounds [A <: Citrus]
181. Covariance Type Param with
Upper Bound
class MyContainer[+A <: Citrus](a: A)
(implicit manifest:
scala.reflect.Manifest[A]) {
private[this] val item = a
def get = item
def contents =
manifest.erasure.getSimpleName
}
182. Covariance Type Param with
Upper Bound
class MyContainer[+A <: Citrus](a: A)
(implicit manifest:
scala.reflect.Manifest[A]) {
private[this] val item = a
def get = item
def contents =
manifest.erasure.getSimpleName
}
183. Covariance Type Param with
Upper Bound
class MyContainer[+A <: Citrus](a: A)
(implicit manifest:
scala.reflect.Manifest[A]) {
private[this] val item = a
def get = item
def contents =
manifest.erasure.getSimpleName
}
val citrusBasket: MyContainer[Citrus] = new
MyContainer[Citrus](new Orange)
citrusBasket.contents // Citrus
val citrusBasket2: MyContainer[Citrus] = new
MyContainer(new Tangelo)
citrusBasket2.contents // Citrus
184. Covariance Type Param with
Upper Bound
class MyContainer[+A <: Citrus](a: A)
(implicit manifest:
scala.reflect.Manifest[A]) {
private[this] val item = a
def get = item
def contents =
manifest.erasure.getSimpleName
}
val citrusBasket6: MyContainer[Fruit] = new
MyContainer(new Orange)
type arguments [Fruit] do not conform to class
MyContainer's type parameter bounds [+A <: Citrus]
185. Contravariance Type Param with
Upper Bound
class MyContainer[-A <: Citrus](a: A)(implicit
manifest: scala.reflect.Manifest[A]) {
private[this] var item = a
def set(a: A) {item = a}
def contents =
manifest.erasure.getSimpleName
}
186. Contravariance Type Param with
Upper Bound
class MyContainer[-A <: Citrus](a: A)(implicit
manifest: scala.reflect.Manifest[A]) {
private[this] var item = a
def set(a: A) {item = a}
def contents =
manifest.erasure.getSimpleName
}
val citrusBasket1: MyContainer[Citrus] = new
MyContainer(new Tangelo)
citrusBasket1.contents // Citrus
val citrusBasket2 = new MyContainer(new Tangelo)
citrusBasket2.contents // Tangelo
187. Contravariance Type Param with
Upper Bound
class MyContainer[-A <: Citrus](a: A)(implicit
manifest: scala.reflect.Manifest[A]) {
private[this] var item = a
def set(a: A) {item = a}
def contents =
manifest.erasure.getSimpleName
}
val citrusBasket1: MyContainer[Citrus] = new
MyContainer(new Tangelo)
citrusBasket1.contents // Citrus
val citrusBasket2 = new MyContainer(new Tangelo)
citrusBasket2.contents // Tangelo
val citrusBasket3 = new MyContainer(new Orange)
citrusBasket3.contents // Orange
188. Contravariance Type Param with
Upper Bound
class MyContainer[-A <: Citrus](a: A)(implicit
manifest: scala.reflect.Manifest[A]) {
private[this] var item = a
def set(a: A) {item = a}
def contents =
manifest.erasure.getSimpleName
}
val citrusBasket6 = new MyContainer(new Apple)
val citrusBasket7 = new MyContainer(new
Orange():Fruit)
val citrusBasket8:MyContainer[Fruit] = new
MyContainer(new Orange())
inferred type arguments do not conform to class
MyContainer's type parameter bounds [-A <:
AboutTypeBounds.this.Citrus]
189. Contravariance Type Param with
both Upper and Lower Bounds
class MyContainer[-A >: Citrus <: AnyRef](a: A)
(implicit manifest: scala.reflect.Manifest[A]) {
private[this] var item = a
def set(a: A) {item = a}
def contents = manifest.erasure.getSimpleName
}
190. Contravariance Type Param with
both Upper and Lower Bounds
class MyContainer[-A >: Citrus <: AnyRef](a: A)
(implicit manifest: scala.reflect.Manifest[A]) {
private[this] var item = a
def set(a: A) {item = a}
def contents = manifest.erasure.getSimpleName
}
191. Contravariance Type Param with
both Upper and Lower Bounds
class MyContainer[-A >: Citrus <: AnyRef](a: A)
(implicit manifest: scala.reflect.Manifest[A]) {
private[this] var item = a
def set(a: A) {item = a}
def contents = manifest.erasure.getSimpleName
}
192. Too many permutations, but just
a reminder...
● Type Variances have little to do with Type
Bounds.
● The left hand type must be undefined, the
other's defined.
● Scala will coerce and infer types for you.
211. Partial Functions
val doubleEvens: PartialFunction[Int, Int] =
new PartialFunction[Int, Int] {
def isDefinedAt(x: Int) = x % 2 == 0
def apply(v1: Int) = v1 * 2
}
212. Partial Functions
val doubleEvens: PartialFunction[Int, Int] =
new PartialFunction[Int, Int] {
def isDefinedAt(x: Int) = x % 2 == 0
def apply(v1: Int) = v1 * 2
}
213. Partial Functions
val doubleEvens: PartialFunction[Int, Int] =
new PartialFunction[Int, Int] {
def isDefinedAt(x: Int) = x % 2 == 0
def apply(v1: Int) = v1 * 2
}
214. Partial Functions
val doubleEvens: PartialFunction[Int, Int] =
new PartialFunction[Int, Int] {
def isDefinedAt(x: Int) = x % 2 == 0
def apply(v1: Int) = v1 * 2
}
val tripleOdds: PartialFunction[Int, Int] =
new PartialFunction[Int, Int] {
def isDefinedAt(x: Int) = x % 2 != 0
def apply(v1: Int) = v1 * 3
}
215. Partial Functions
val doubleEvens: PartialFunction[Int, Int] =
new PartialFunction[Int, Int] {
def isDefinedAt(x: Int) = x % 2 == 0
def apply(v1: Int) = v1 * 2
}
val tripleOdds: PartialFunction[Int, Int] =
new PartialFunction[Int, Int] {
def isDefinedAt(x: Int) = x % 2 != 0
def apply(v1: Int) = v1 * 3
}
val whatToDo = doubleEvens orElse tripleOdds
216. Partial Functions
val doubleEvens: PartialFunction[Int, Int] =
new PartialFunction[Int, Int] {
def isDefinedAt(x: Int) = x % 2 == 0
def apply(v1: Int) = v1 * 2
}
val tripleOdds: PartialFunction[Int, Int] =
new PartialFunction[Int, Int] {
def isDefinedAt(x: Int) = x % 2 != 0
def apply(v1: Int) = v1 * 3
}
val whatToDo = doubleEvens orElse tripleOdds
whatToDo(3) // 9
whatToDo(4) // 8
217. Partial Functions as case
statements
val doubleEvens: PartialFunction[Int, Int] =
new PartialFunction[Int, Int] {
def isDefinedAt(x: Int) = x % 2 == 0
def apply(v1: Int) = v1 * 2
}
Can become...
val doubleEvens: PartialFunction[Int, Int] = {
case x: Int if ((x % 2) == 0) => x * 2
}
218. Partial Functions as case
statements
val doubleEvens: PartialFunction[Int, Int] = {
case x: Int if ((x % 2) == 0) => x * 2
}
val tripleOdds: PartialFunction[Int, Int] = {
case x: Int if ((x % 2) != 0) => x * 3
}
val whatToDo = doubleEvens orElse tripleOdds
whatToDo(3) // 9
whatToDo(4) // 8
219. andThen More Partial Functions
val doubleEvens: PartialFunction[Int, Int] = {
case x: Int if ((x % 2) == 0) => x * 2
}
val tripleOdds: PartialFunction[Int, Int] = {
case x: Int if ((x % 2) != 0) => x * 3
}
val addFive = (x: Int) => x + 5
val whatToDo = doubleEvens orElse tripleOdds andThen addFive
whatToDo(3) // 14
whatToDo(4) // 13
220. andThen More Partial Functions
val doubleEvens: PartialFunction[Int, Int] = {
case x: Int if ((x % 2) == 0) => x * 2
}
val tripleOdds: PartialFunction[Int, Int] = {
case x: Int if ((x % 2) != 0) => x * 3
}
val addFive = (x: Int) => x + 5
val whatToDo = doubleEvens orElse tripleOdds andThen addFive
whatToDo(3) // 14
whatToDo(4) // 13
221. andThen More Partial Functions
val doubleEvens: PartialFunction[Int, Int] = {
case x: Int if ((x % 2) == 0) => x * 2
}
val tripleOdds: PartialFunction[Int, Int] = {
case x: Int if ((x % 2) != 0) => x * 3
}
val addFive = (x: Int) => x + 5
val whatToDo = doubleEvens orElse tripleOdds andThen addFive
whatToDo(3) // 14
whatToDo(4) // 13
222. andThen More Partial Functions
val doubleEvens: PartialFunction[Int, Int] = {
case x: Int if ((x % 2) == 0) => x * 2
}
val tripleOdds: PartialFunction[Int, Int] = {
case x: Int if ((x % 2) != 0) => x * 3
}
val addFive = (x: Int) => x + 5
val whatToDo = doubleEvens orElse tripleOdds andThen addFive
whatToDo(3) // 14
whatToDo(4) // 13
223. andThen More Partial Functions
val doubleEvens: PartialFunction[Int, Int] = {
case x: Int if ((x % 2) == 0) => x * 2
}
val tripleOdds: PartialFunction[Int, Int] = {
case x: Int if ((x % 2) != 0) => x * 3
}
val addFive = (x: Int) => x + 5
val whatToDo = doubleEvens orElse tripleOdds andThen addFive
whatToDo(3) // 14
whatToDo(4) // 13
224. andThen More Compound Partial
Functions
val doubleEvens: PartialFunction[Int, Int] = {
case x: Int if ((x % 2) == 0) => x * 2
}
val tripleOdds: PartialFunction[Int, Int] = {
case x: Int if ((x % 2) != 0) => x * 3
}
val printEven: PartialFunction[Int, String] = {
case x: Int if ((x % 2) == 0) => "Even"
}
val printOdd: PartialFunction[Int, String] = {
case x: Int if ((x % 2) != 0) => "Odd"
}
val whatToDo = doubleEvens orElse tripleOdds andThen
(printEven orElse printOdd)
whatToDo(3) // Odd
whatToDo(4) // Even
225. andThen More Compound Partial
Functions
val doubleEvens: PartialFunction[Int, Int] = {
case x: Int if ((x % 2) == 0) => x * 2
}
val tripleOdds: PartialFunction[Int, Int] = {
case x: Int if ((x % 2) != 0) => x * 3
}
val printEven: PartialFunction[Int, String] = {
case x: Int if ((x % 2) == 0) => "Even"
}
val printOdd: PartialFunction[Int, String] = {
case x: Int if ((x % 2) != 0) => "Odd"
}
val whatToDo = doubleEvens orElse tripleOdds andThen
(printEven orElse printOdd)
whatToDo(3) // Odd
whatToDo(4) // Even
226. andThen More Compound Partial
Functions
val doubleEvens: PartialFunction[Int, Int] = {
case x: Int if ((x % 2) == 0) => x * 2
}
val tripleOdds: PartialFunction[Int, Int] = {
case x: Int if ((x % 2) != 0) => x * 3
}
val printEven: PartialFunction[Int, String] = {
case x: Int if ((x % 2) == 0) => "Even"
}
val printOdd: PartialFunction[Int, String] = {
case x: Int if ((x % 2) != 0) => "Odd"
}
val whatToDo = doubleEvens orElse tripleOdds andThen
(printEven orElse printOdd)
whatToDo(3) // Odd
whatToDo(4) // Even
227. andThen More Compound Partial
Functions
val doubleEvens: PartialFunction[Int, Int] = {
case x: Int if ((x % 2) == 0) => x * 2
}
val tripleOdds: PartialFunction[Int, Int] = {
case x: Int if ((x % 2) != 0) => x * 3
}
val printEven: PartialFunction[Int, String] = {
case x: Int if ((x % 2) == 0) => "Even"
}
val printOdd: PartialFunction[Int, String] = {
case x: Int if ((x % 2) != 0) => "Odd"
}
val whatToDo = doubleEvens orElse tripleOdds andThen
(printEven orElse printOdd)
whatToDo(3) should be("Odd")
whatToDo(4) should be("Even")
238. Generalized Type Constraints
class Pair[T](val first: T, val second: T) {
def smaller = if (first < second) first
else second
}
*This only works if type T is is Ordered[T]
239. Generalized Type Constraints
class Pair[T <: Ordered[T]]
(val first: T, val second: T) {
def smaller = if (first < second) first
else second
}
*Not all T is Ordered[T]
240. Generalized Type Constraints
class Pair[T]
(val first: T, val second: T) {
def smaller(implicit ev: T <:< Ordered[T]) =
if (first < second) first else second
}
241. Generalized Type Constraints
class Pair[T]
(val first: T, val second: T) {
def smaller(implicit ev: T <:< Ordered[T]) =
if (first < second) first else second
}