Code Examples for

Programming in Scala, Fourth Edition

Return to chapter index

8 Functions and Closures

Sample run of chapter's interpreter examples

8.1 Methods


// In file functions-and-closures/LongLines.scala import scala.io.Source object LongLines { def processFile(filename: String, width: Int) = { val source = Source.fromFile(filename) for (line <- source.getLines()) processLine(filename, width, line) } private def processLine(filename: String, width: Int, line: String) = { if (line.length > width) println(filename + ": " + line.trim) } }
// In file functions-and-closures/LongLines2.scala object FindLongLines { def main(args: Array[String]) = { val width = args(0).toInt for (arg <- args.drop(1)) LongLines.processFile(arg, width) } }
$ scala FindLongLines 45 LongLines.scala LongLines.scala: def processFile(filename: String, width: Int) = {

8.2 Local functions


// In file functions-and-closures/LongLines2.scala def processFile(filename: String, width: Int) = { def processLine(filename: String, width: Int, line: String) = { if (line.length > width) println(filename + ": " + line.trim) } val source = Source.fromFile(filename) for (line <- source.getLines()) { processLine(filename, width, line) } }
// In file functions-and-closures/LongLines3.scala import scala.io.Source object LongLines { def processFile(filename: String, width: Int) = { def processLine(line: String) = { if (line.length > width) println(filename + ": " + line.trim) } val source = Source.fromFile(filename) for (line <- source.getLines()) processLine(line) } }

8.3 First-class functions


(x: Int) => x + 1
scala> var increase = (x: Int) => x + 1 increase: Int => Int = $$Lambda$988/1232424564@cf01c2e scala> increase(10) res0: Int = 11
scala> increase = (x: Int) => x + 9999 mutated increase scala> increase(10) res1: Int = 10009
scala> increase = (x: Int) => { | println("We") | println("are") | println("here!") | x + 1 | } mutated increase scala> increase(10) We are here! res2: Int = 11
scala> val someNumbers = List(-11, -10, -5, 0, 5, 10) someNumbers: List[Int] = List(-11, -10, -5, 0, 5, 10) scala> someNumbers.foreach((x: Int) => println(x)) -11 -10 -5 0 5 10
scala> someNumbers.filter((x: Int) => x > 0) res4: List[Int] = List(5, 10)

8.4 Short forms of function literals


scala> someNumbers.filter((x) => x > 0) res5: List[Int] = List(5, 10)
scala> someNumbers.filter(x => x > 0) res6: List[Int] = List(5, 10)

8.5 Placeholder syntax


scala> someNumbers.filter(_ > 0) res7: List[Int] = List(5, 10)
scala> someNumbers.filter(x => x > 0) res8: List[Int] = List(5, 10)
scala> val f = _ + _ ^ error: missing parameter type for expanded function ((x$1: <error>, x$2) => x$1.$plus(x$2))
scala> val f = (_: Int) + (_: Int) f: (Int, Int) => Int = $$Lambda$1075/1481958694@289fff3c scala> f(5, 10) res9: Int = 15

8.6 Partially applied functions


// In file functions-and-closures/Misc.scala someNumbers.foreach(println _)
// In file functions-and-closures/Misc.scala someNumbers.foreach(x => println(x))
scala> def sum(a: Int, b: Int, c: Int) = a + b + c sum: (a: Int, b: Int, c: Int)Int
scala> sum(1, 2, 3) res10: Int = 6
scala> val a = sum _ a: (Int, Int, Int) => Int = $$Lambda$1091/1149618736@6415112c
scala> a(1, 2, 3) res11: Int = 6
scala> a.apply(1, 2, 3) res12: Int = 6
scala> val b = sum(1, _: Int, 3) b: Int => Int = $$Lambda$1092/457198113@280aa1bd
scala> b(2) res13: Int = 6
scala> b(5) res14: Int = 9
// In file functions-and-closures/Misc.scala someNumbers.foreach(println _)
// In file functions-and-closures/Misc.scala someNumbers.foreach(println)
scala> val c = sum error: missing argument list for method sum Unapplied methods are only converted to functions when a function type is expected. You can make this conversion explicit by writing `sum _` or `sum(_,_,_)` instead of `sum`. scala> val d = sum _ d: (Int, Int, Int) => Int = $$Lambda$1095/598308875@12223aed scala> d(10, 20, 30) res14: Int = 60

8.7 Closures


(x: Int) => x + more // how much more?
scala> (x: Int) => x + more ^ error: not found: value more
scala> var more = 1 more: Int = 1 scala> val addMore = (x: Int) => x + more addMore: Int => Int = $$Lambda$1103/2125513028@11cb348c scala> addMore(10) res16: Int = 11
scala> more = 9999 mutated more scala> addMore(10) res17: Int = 10009
scala> val someNumbers = List(-11, -10, -5, 0, 5, 10) someNumbers: List[Int] = List(-11, -10, -5, 0, 5, 10) scala> var sum = 0 sum: Int = 0 scala> someNumbers.foreach(sum += _)
scala> sum res19: Int = -11
def makeIncreaser(more: Int) = (x: Int) => x + more
scala> val inc1 = makeIncreaser(1) inc1: Int => Int = $$Lambda$1126/1042315811@4262a8d2 scala> val inc9999 = makeIncreaser(9999) inc9999: Int => Int = $$Lambda$1126/1042315811@4c8bbc5e
scala> inc1(10) res20: Int = 11 scala> inc9999(10) res21: Int = 10009

8.8 Special function call forms


scala> def echo(args: String*) = | for (arg <- args) println(arg) echo: (args: String*)Unit
scala> echo() scala> echo("one") one scala> echo("hello", "world!") hello world!
scala> val seq = Seq("What's", "up", "doc?") seq: Seq[String] = Seq(What's, up, doc?) scala> echo(seq) ^ error: type mismatch; found : Seq[String] required: String
scala> echo(seq: _*) What's up doc?
scala> def speed(distance: Float, time: Float): Float = | distance / time speed: (distance: Float, time: Float)Float scala> speed(100, 10) res27: Float = 10.0
scala> speed(distance = 100, time = 10) res28: Float = 10.0
scala> speed(time = 10, distance = 100) res29: Float = 10.0
// In file functions-and-closures/NamedDefault.scala def printTime(out: java.io.PrintStream = Console.out) = out.println("time = " + System.currentTimeMillis())
// In file functions-and-closures/NamedDefault.scala def printTime2(out: java.io.PrintStream = Console.out, divisor: Int = 1) = out.println("time = " + System.currentTimeMillis()/divisor)
printTime2(out = Console.err)
printTime2(divisor = 1000)

8.9 Tail recursion


// In file functions-and-closures/Approximate.scala def approximate(guess: Double): Double = if (isGoodEnough(guess)) guess else approximate(improve(guess))
// In file functions-and-closures/Approximate.scala def approximateLoop(initialGuess: Double): Double = { var guess = initialGuess while (!isGoodEnough(guess)) guess = improve(guess) guess }
// In file functions-and-closures/TailRecursion.scala def boom(x: Int): Int = if (x == 0) throw new Exception("boom!") else boom(x - 1) + 1
scala> boom(3) java.lang.Exception: boom! at .boom(<console>:5) at .boom(<console>:6) at .boom(<console>:6) at .boom(<console>:6) at .<init>(<console>:6) ...
public double approximate(double); Code: 0: aload_0 1: astore_3 2: aload_0 3: dload_1 4: invokevirtual #24; //Method isGoodEnough:(D)Z 7: ifeq 12 10: dload_1 11: dreturn 12: aload_0 13: dload_1 14: invokevirtual #27; //Method improve:(D)D 17: dstore_1 18: goto 2
// In file functions-and-closures/TailRecursion.scala def bang(x: Int): Int = if (x == 0) throw new Exception("bang!") else bang(x - 1)
scala> bang(5) java.lang.Exception: bang! at .bang(<console>:5) at .<init>(<console>:6) ...
-g:notailcalls
scala> bang(5) java.lang.Exception: bang! at .bang(<console>:5) at .bang(<console>:5) at .bang(<console>:5) at .bang(<console>:5) at .bang(<console>:5) at .bang(<console>:5) at .<init>(<console>:6) ...
// In file functions-and-closures/Misc.scala def isEven(x: Int): Boolean = if (x == 0) true else isOdd(x - 1) def isOdd(x: Int): Boolean = if (x == 0) false else isEven(x - 1)
// In file functions-and-closures/Misc.scala val funValue = nestedFun _ def nestedFun(x: Int) : Unit = { if (x != 0) { println(x); funValue(x - 1) } }

8.10 Conclusion

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

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

and:

http://booksites.artima.com/programming_in_scala_4ed

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