Code Examples for

Programming in Scala, Fifth Edition

Return to chapter index

21 Givens

Sample run of chapter's interpreter examples

21.1 How it works


class PreferredPrompt(val preference: String)
object Greeter: def greet(name: String)(using prompt: PreferredPrompt) = println(s"Welcome, $name. The system is ready.") println(prompt.preference)
// In file givens/JillsPrefs.scala object JillsPrefs: given prompt: PreferredPrompt = PreferredPrompt("Your wish> ")
scala> Greeter.greet("Jill") 1 |Greeter.greet("Jill") | ^ |no implicit argument of type PreferredPrompt was found |for parameter prompt of method greet in object Greeter
scala> import JillsPrefs.prompt scala> Greeter.greet("Jill") Welcome, Jill. The system is ready. Your wish>
scala> Greeter.greet("Jill")(JillsPrefs.prompt) 1 |Greeter.greet("Jill")(JillsPrefs.prompt) |^^^^^^^^^^^^^^^^^^^^^ |method greet in object Greeter does not take more |parameters
scala> Greeter.greet("Jill")(using JillsPrefs.prompt) Welcome, Jill. The system is ready. Your wish>
scala> Greeter.greet("Joe") 1 |Greeter.greet("Joe") | ^ |no implicit argument of type PreferredPrompt was found |for parameter prompt of method greet in object Greeter
scala> import JoesPrefs.{prompt, drink}
scala> Greeter.greet("Joe")(using prompt, drink) Welcome, Joe. The system is ready. But while you work, why not enjoy a cup of tea? relax>
scala> Greeter.greet("Joe") Welcome, Joe. The system is ready. But while you work, why not enjoy a cup of tea? relax>
// In file givens/prefs.scala class PreferredPrompt(val preference: String) class PreferredDrink(val preference: String) object Greeter: def greet(name: String)(using prompt: PreferredPrompt, drink: PreferredDrink) = println(s"Welcome, $name. The system is ready.") print("But while you work, ") println(s"why not enjoy a cup of ${drink.preference}?") println(prompt.preference) object JoesPrefs: given prompt: PreferredPrompt = PreferredPrompt("relax> ") given drink: PreferredDrink = PreferredDrink("tea")

21.2 Parameterized given types


// Does not compile. def isort[T](xs: List[T]): List[T] = if xs.isEmpty then Nil else insert(xs.head, isort(xs.tail)) def insert[T](x: T, xs: List[T]): List[T] = if xs.isEmpty || x <= xs.head then x :: xs else xs.head :: insert(x, xs.tail)
6 | if xs.isEmpty || x <= xs.head then x :: xs | ^^^^ | value <= is not a member of T, ...
// In file givens/isort1.scala def isort[T](xs: List[T])(lteq: (T, T) => Boolean): List[T] = if xs.isEmpty then Nil else insert(xs.head, isort(xs.tail)(lteq))(lteq) def insert[T](x: T, xs: List[T]) (lteq: (T, T) => Boolean): List[T] = if xs.isEmpty || lteq(x, xs.head) then x :: xs else xs.head :: insert(x, xs.tail)(lteq)
// In file givens/isort1.scala isort(List(4, -10, 10))((x: Int, y: Int) => x <= y) // List(-10, 4, 10) isort(List("cherry", "blackberry", "apple", "pear")) ((x: String, y: String) => x.compareTo(y) <= 0) // List(apple, blackberry, cherry, pear) isort(List(Rational(7, 8), Rational(5, 6), Rational(1, 2))) ((x: Rational, y: Rational) => x.numer * y.denom <= x.denom * y.numer) // List(1/2, 5/6, 7/8)
// In file givens/isort1.scala isort(List(4, -10, 10))((x, y) => x <= y) // List(-10, 4, 10) isort(List("cherry", "blackberry", "apple", "pear")) ((x, y) => x.compareTo(y) < 1) // List(apple, blackberry, cherry, pear) isort(List(Rational(7, 8), Rational(5, 6), Rational(1, 2))) ((x, y) => x.numer * y.denom <= x.denom * y.numer) // List(1/2, 5/6, 7/8)
// In file givens/Ord.scala trait Ord[T]: def compare(x: T, y: T): Int def lteq(x: T, y: T): Boolean = compare(x, y) < 1
// In file givens/rationalOrd.scala def isort[T](xs: List[T])(using ord: Ord[T]): List[T] = if xs.isEmpty then Nil else insert(xs.head, isort(xs.tail)) def insert[T](x: T, xs: List[T]) (using ord: Ord[T]): List[T] = if xs.isEmpty || ord.lteq(x, xs.head) then x :: xs else xs.head :: insert(x, xs.tail)
object Ord: // (Not yet idiomatic) given intOrd: Ord[Int] = new Ord[Int]: def compare(x: Int, y: Int) = if x == y then 0 else if x > y then 1 else -1
object Ord: // This is idiomatic given intOrd: Ord[Int] with def compare(x: Int, y: Int) = if x == y then 0 else if x > y then 1 else -1
isort(List(10, 2, -10)) // List(-10, 2, 10)
// In file givens/string-ord.scala // Added to object Ord given stringOrd: Ord[String] with def compare(s: String, t: String) = s.compareTo(t)
// In file givens/isort2.scala isort(List("mango", "jackfruit", "durian")) // List(durian, jackfruit, mango)

21.3 Anonymous givens


val age = 42
// In file givens/rev-ord.scala given revIntOrd: Ord[Int] with def compare(x: Int, y: Int) = if x == y then 0 else if x > y then -1 else 1 given revStringOrd: Ord[String] with def compare(s: String, t: String) = -s.compareTo(t)
// In file givens/ord-int-string-compare.scala given Ord[Int] with def compare(x: Int, y: Int) = if x == y then 0 else if x > y then -1 else 1 given Ord[String] with def compare(s: String, t: String) = -s.compareTo(t)

21.4 Parameterized givens as typeclasses


// In file givens/rationalOrd.scala object Rational: given rationalOrd: Ord[Rational] with def compare(x: Rational, y: Rational) = if x.numer * y.denom < x.denom * y.numer then -1 else if x.numer * y.denom > x.denom * y.numer then 1 else 0
// In file givens/rationalOrd.scala isort(List(Rational(4, 5), Rational(1, 2), Rational(2, 3))) // List(1/2, 2/3, 4/5)
// In file givens/isort-param.scala def isort[T](xs: List[T])(using Ordering[T]): List[T] = if xs.isEmpty then Nil else insert(xs.head, isort(xs.tail)) def insert[T](x: T, xs: List[T]) (using ord: Ordering[T]): List[T] = if xs.isEmpty || ord.lteq(x, xs.head) then x :: xs else xs.head :: insert(x, xs.tail)
// In file givens/msort.scala def msort[T](xs: List[T])(using ord: Ordering[T]): List[T] = def merge(xs: List[T], ys: List[T]): List[T] = (xs, ys) match case (Nil, _) => ys case (_, Nil) => xs case (x :: xs1, y :: ys1) => if ord.lt(x, y) then x :: merge(xs1, ys) else y :: merge(xs, ys1) val n = xs.length / 2 if n == 0 then xs else val (ys, zs) = xs.splitAt(n) merge(msort(ys), msort(zs))

21.5 Given imports


// In file givens/TomsPrefs.scala object TomsPrefs: val favoriteColor = "blue" def favoriteFood = "steak" given prompt: PreferredPrompt = PreferredPrompt("enjoy> ") given drink: PreferredDrink = PreferredDrink("red wine") given prefPromptOrd: Ordering[PreferredPrompt] with def compare(x: PreferredPrompt, y: PreferredPrompt) = x.preference.compareTo(y.preference) given prefDrinkOrd: Ordering[PreferredDrink] with def compare(x: PreferredDrink, y: PreferredDrink) = x.preference.compareTo(y.preference)
// In file givens/TomsPrefs-import.scala // imports only favoriteColor and favoriteFood import TomsPrefs.*
// In file givens/TomsPrefs-import.scala import TomsPrefs.prompt // imports prompt
// In file givens/TomsPrefs-import.scala // imports prompt, drink, prefPromptOrd, and prefDrinkOrd import TomsPrefs.given
// In file givens/TomsPrefs-import.scala // imports drink, because it is a given of // type PreferredDrink import TomsPrefs.{given PreferredDrink}
// In file givens/prefPromptOrd.scala // imports prefPromptOrd and prefDrinkOrd import TomsPrefs.{given Ordering[PreferredPrompt], given Ordering[PreferredDrink]}
// In file givens/TomsPrefs-import.scala // imports prefPromptOrd and prefDrinkOrd import TomsPrefs.{given Ordering[?]}

21.6 Rules for context parameters


given amysPrompt: PreferredPrompt = PreferredPrompt("hi> ")
// In file givens/rational-compare.scala object Rational: given rationalOrdering: Ordering[Rational] with def compare(x: Rational, y: Rational) = if x.numer * y.denom < x.denom * y.numer then -1 else if x.numer * y.denom > x.denom * y.numer then 1 else 0
// In file givens/TomsPrefs-import.scala import TomsPrefs.prefPromptOrd

21.7 When multiple givens apply


// In file givens/PreferredPrompt.scala class PreferredPrompt(val preference: String) object Greeter: def greet(name: String)(using prompt: PreferredPrompt) = println(s"Welcome, $name. The system is ready.") println(prompt.preference) object JillsPrefs: given jillsPrompt: PreferredPrompt = PreferredPrompt("Your wish> ") object JoesPrefs: given joesPrompt: PreferredPrompt = PreferredPrompt("relax> ")
scala> import JillsPrefs.jillsPrompt scala> import JoesPrefs.joesPrompt
scala> Greeter.greet("Who's there?") 1 |Greeter.greet("Who's there?") | ^ |ambiguous implicit arguments: both given instance |joesPrompt in object JoesPrefs and given instance |jillsPrompt in object JillsPrefs match type |PreferredPrompt of parameter prompt of method |greet in object Greeter

21.8 Debugging givens


Mocha.enjoy("reader")(Mocha.pref)
// In file givens/ImplicitsExample.scala object Mocha: class PreferredDrink(val preference: String) given pref: PreferredDrink = new PreferredDrink("mocha") def enjoy(name: String)(using drink: PreferredDrink): Unit = print(s"Welcome, $name") print(". Enjoy a ") print(drink.preference) println("!") def callEnjoy: Unit = enjoy("reader")
$ scalac -Xprint:typer Mocha.scala package <empty> { final lazy module val Mocha: Mocha$ = new Mocha$() def callEnjoy: Unit = Mocha.enjoy("reader")(Mocha.pref) final module class Mocha$() extends Object() { this: Mocha.type => // ... final lazy given val pref: Mocha.PreferredDrink = new Mocha.PreferredDrink("mocha") def enjoy(name: String)(using drink: Mocha.PreferredDrink): Unit = { print( _root_.scala.StringContext.apply(["Welcome, ","" : String]:String*).s([name : Any]:Any*) ) print(". Enjoy a ") print(drink.preference) println("!") } def callEnjoy: Unit = Mocha.enjoy("reader")(Mocha.pref) } }

21.9 Conclusion

For more information about Programming in Scala, Fifth Edition (the "Stairway Book"), please visit:

http://www.artima.com/shop/programming_in_scala_5ed

and:

http://booksites.artima.com/programming_in_scala_5ed

Copyright © 2007-2020 Artima, Inc. All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.