Code Examples for

Programming in Scala

Return to chapter index

21 Implicit Conversions and Parameters

Sample run of chapter's interpreter examples

21.1 Implicit conversions


// In file implicits/String2Seq.scala implicit def stringWrapper(s: String) = new RandomAccessSeq[Char] { def length = s.length def apply(i: Int) = s.charAt(i) }
scala> stringWrapper("abc123") exists (_.isDigit) res0: Boolean = true
scala> "abc123" exists (_.isDigit) res1: Boolean = true
// In file implicits/String2Seq.scala def printWithSpaces(seq: RandomAccessSeq[Char]) = seq mkString " "
scala> printWithSpaces("xyz") res2: String = x y z
scala> printWithSpaces(stringWrapper("xyz")) res3: String = x y z

21.2 Rules for implicits


// In file implicits/Misc.scala implicit def intToString(x: Int) = x.toString
object Dollar { implicit def dollarToEuro(x: Dollar): Euro = ... } class Dollar { ... }
object MyConversions { implicit def stringWrapper(s: String): RandomAccessSeq[Char] = ... implicit def intToString(x: Int): String = ... }
import MyConversions.stringWrapper ... // code making use of stringWrapper

21.3 Implicit conversion to an expected type


scala> val i: Int = 3.5 <console>:5: error: type mismatch; found : Double(3.5) required: Int val i: Int = 3.5 ^
scala> implicit def doubleToInt(x: Double) = x.toInt doubleToInt: (Double)Int scala> val i: Int = 3.5 i: Int = 3
val i: Int = doubleToInt(3.5)
// In file implicits/Misc.scala implicit def int2double(x: Int): Double = x.toDouble

21.4 Converting the receiver


class Rational(n: Int, d: Int) { ... def + (that: Rational): Rational = ... def + (that: Int): Rational = ... }
scala> val oneHalf = new Rational(1, 2) oneHalf: Rational = 1/2 scala> oneHalf + oneHalf res4: Rational = 1/1 scala> oneHalf + 1 res5: Rational = 3/2
scala> 1 + oneHalf <console>:6: error: overloaded method value + with alternatives (Double)Double <and> ... cannot be applied to (Rational) 1 + oneHalf ^
scala> implicit def intToRational(x: Int) = | new Rational(x, 1) intToRational: (Int)Rational
scala> 1 + oneHalf res6: Rational = 3/2
intToRational(1) + oneHalf
// In file implicits/Misc.scala Map(1 -> "one", 2 -> "two", 3 -> "three")
package scala object Predef { class ArrowAssoc[A](x: A) { def -> [B](y: B): Tuple2[A, B] = Tuple2(x, y) } implicit def any2ArrowAssoc[A](x: A): ArrowAssoc[A] = new ArrowAssoc(x) ... }

21.5 Implicit parameters


class PreferredPrompt(val preference: String)
object Greeter { def greet(name: String)(implicit prompt: PreferredPrompt) { println("Welcome, "+ name +". The system is ready.") println(prompt.preference) } }
scala> val bobsPrompt = new PreferredPrompt("relax> ") bobsPrompt: PreferredPrompt = PreferredPrompt@ece6e1 scala> Greeter.greet("Bob")(bobsPrompt) Welcome, Bob. The system is ready. relax>
object JoesPrefs { implicit val prompt = new PreferredPrompt("Yes, master> ") }
scala> Greeter.greet("Joe") <console>:7: error: no implicit argument matching parameter type PreferredPrompt was found. Greeter.greet("Joe") ^
scala> import JoesPrefs._ import JoesPrefs._ scala> Greeter.greet("Joe") Welcome, Joe. The system is ready. Yes, master>
class PreferredPrompt(val preference: String) class PreferredDrink(val preference: String) object Greeter { def greet(name: String)(implicit prompt: PreferredPrompt, drink: PreferredDrink) { println("Welcome, "+ name +". The system is ready.") print("But while you work, ") println("why not enjoy a cup of "+ drink.preference +"?") println(prompt.preference) } } object JoesPrefs { implicit val prompt = new PreferredPrompt("Yes, master> ") implicit val drink = new PreferredDrink("tea") }
scala> Greeter.greet("Joe") <console>:8: error: no implicit argument matching parameter type PreferredPrompt was found. Greeter.greet("Joe") ^
scala> import JoesPrefs._ import JoesPrefs._
scala> Greeter.greet("Joe")(prompt, drink) Welcome, Joe. The system is ready. But while you work, why not enjoy a cup of tea? Yes, master>
scala> Greeter.greet("Joe") Welcome, Joe. The system is ready. But while you work, why not enjoy a cup of tea? Yes, master>
// In file implicits/Misc.scala def maxListUpBound[T <: Ordered[T]](elements: List[T]): T = elements match { case List() => throw new IllegalArgumentException("empty list!") case List(x) => x case x :: rest => val maxRest = maxListUpBound(rest) if (x > maxRest) x else maxRest }
// In file implicits/MaxList1.scala def maxListImpParm[T](elements: List[T]) (implicit orderer: T => Ordered[T]): T = elements match { case List() => throw new IllegalArgumentException("empty list!") case List(x) => x case x :: rest => val maxRest = maxListImpParm(rest)(orderer) if (orderer(x) > maxRest) x else maxRest }
scala> maxListImpParm(List(1,5,10,3)) res10: Int = 10 scala> maxListImpParm(List(1.5, 5.2, 10.7, 3.14159)) res11: Double = 10.7 scala> maxListImpParm(List("one", "two", "three")) res12: java.lang.String = two
def maxListPoorStyle[T](elments: List[T]) (implicit orderer: (T, T) => Boolean): T

21.6 View bounds


// In file implicits/Misc.scala def maxList[T](elements: List[T]) (implicit orderer: T => Ordered[T]): T = elements match { case List() => throw new IllegalArgumentException("empty list!") case List(x) => x case x :: rest => val maxRest = maxList(rest) // (orderer) is implicit if (x > maxRest) x // orderer(x) is implicit else maxRest }
// In file implicits/Misc.scala def maxList[T](elements: List[T]) (implicit converter: T => Ordered[T]): T = // same body...
// In file implicits/Misc.scala def maxList[T](elements: List[T]) (implicit iceCream: T => Ordered[T]): T = // same body...
// In file implicits/MaxList2.scala def maxList[T <% Ordered[T]](elements: List[T]): T = elements match { case List() => throw new IllegalArgumentException("empty list!") case List(x) => x case x :: rest => val maxRest = maxList(rest) // (orderer) is implicit if (x > maxRest) x // orderer(x) is implicit else maxRest }
implicit def identity[A](x: A): A = x
// In file implicits/mocha.scala object Mocha extends Application { class PreferredDrink(val preference: String) implicit val pref = new PreferredDrink("mocha") def enjoy(name: String)(implicit drink: PreferredDrink) { print("Welcome, "+ name) print(". Enjoy a ") print(drink.preference) println("!") } enjoy("reader") }
$ scalac -Xprint:typer mocha.scala [[syntax trees at end of typer]]// Scala source: mocha.scala package <empty> { final object Mocha extends java.lang.Object with Application with ScalaObject { // ... private[this] val pref: Mocha.PreferredDrink = new Mocha.this.PreferredDrink("mocha"); implicit <stable> <accessor> def pref: Mocha.PreferredDrink = Mocha.this.pref; def enjoy(name: String) (implicit drink: Mocha.PreferredDrink): Unit = { scala.this.Predef.print("Welcome, ".+(name)); scala.this.Predef.print(". Enjoy a "); scala.this.Predef.print(drink.preference); scala.this.Predef.println("!") }; Mocha.this.enjoy("reader")(Mocha.this.pref) } }

21.7 Debugging implicits


scala> val chars: List[Char] = "xyz" <console>:12: error: type mismatch; found : java.lang.String("xyz") required: List[Char] val chars: List[Char] = "xyz" ^
scala> val chars: List[Char] = stringWrapper("xyz") <console>:12: error: type mismatch; found : java.lang.Object with RandomAccessSeq[Char] required: List[Char] val chars: List[Char] = stringWrapper("xyz") ^
enjoy("reader")
Mocha.this.enjoy("reader")(Mocha.this.pref)

21.8 Conclusion

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

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

and:

http://booksites.artima.com/programming_in_scala

Copyright © 2007-2008 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.