Code Examples for

Programming in Scala, Fifth Edition

Return to chapter index

9 Control Abstraction

Sample run of chapter's interpreter examples

9.1 Reducing code duplication


// In file control-abstraction/Files1.scala object FileMatcher: private def filesHere = (new java.io.File(".")).listFiles def filesEnding(query: String) = for file <- filesHere if file.getName.endsWith(query) yield file
// In file control-abstraction/Files1.scala def filesContaining(query: String) = for file <- filesHere if file.getName.contains(query) yield file
// In file control-abstraction/Files1.scala def filesRegex(query: String) = for file <- filesHere if file.getName.matches(query) yield file
def filesMatching(query: String, method) = for file <- filesHere if file.getName.method(query) yield file
// In file control-abstraction/Files2.scala def filesMatching(query: String, matcher: (String, String) => Boolean) = for file <- filesHere if matcher(file.getName, query) yield file
// In file control-abstraction/Files2.scala def filesEnding(query: String) = filesMatching(query, _.endsWith(_)) def filesContaining(query: String) = filesMatching(query, _.contains(_)) def filesRegex(query: String) = filesMatching(query, _.matches(_))
(fileName: String, query: String) => fileName.endsWith(query)
// In file control-abstraction/Files.scala object FileMatcher: private def filesHere = (new java.io.File(".")).listFiles private def filesMatching(matcher: String => Boolean) = for file <- filesHere if matcher(file.getName) yield file def filesEnding(query: String) = filesMatching(_.endsWith(query)) def filesContaining(query: String) = filesMatching(_.contains(query)) def filesRegex(query: String) = filesMatching(_.matches(query))

9.2 Simplifying client code


def containsNeg(nums: List[Int]): Boolean = var exists = false for num <- nums do if num < 0 then exists = true exists
containsNeg(List(1, 2, 3, 4)) // false containsNeg(List(1, 2, -3, 4)) // true
def containsNeg(nums: List[Int]) = nums.exists(_ < 0)
containsNeg(Nil) // false containsNeg(List(0, -1, -2)) // true
def containsOdd(nums: List[Int]): Boolean = var exists = false for num <- nums do if num % 2 == 1 then exists = true exists
def containsOdd(nums: List[Int]) = nums.exists(_ % 2 == 1)

9.3 Currying


def plainOldSum(x: Int, y: Int) = x + y plainOldSum(1, 2) // 3
def curriedSum(x: Int)(y: Int) = x + y curriedSum(1)(2) // 3
def first(x: Int) = (y: Int) => x + y
val second = first(1) // second has type Int => Int
second(2) // 3
val onePlus = curriedSum(1) // onePlus has type Int => Int
onePlus(2) // 3
val twoPlus = curriedSum(2) twoPlus(2) // 4

9.4 Writing new control structures


def twice(op: Double => Double, x: Double) = op(op(x)) twice(_ + 1, 5) // 7.0
// In file control-abstraction/WithPrintWriter1.scala def withPrintWriter(file: File, op: PrintWriter => Unit) = val writer = new PrintWriter(file) try op(writer) finally writer.close()
// In file control-abstraction/WithPrintWriter1.scala withPrintWriter( new File("date.txt"), writer => writer.println(new java.util.Date) )
val s = "Hello, world!" s.charAt(1) // 'e'
s.charAt { 1 } // 'e'
s.substring { 7, 9 } 1 |s.substring { 7, 9 } | ^ | end of statement expected but ',' found 1 |s.substring { 7, 9 } | ^ | ';' expected, but integer literal found
s.substring(7, 9) // "wo"
// In file control-abstraction/WithPrintWriter2.scala def withPrintWriter(file: File)(op: PrintWriter => Unit) = val writer = new PrintWriter(file) try op(writer) finally writer.close()
// In file control-abstraction/WithPrintWriter2.scala val file = new File("date.txt") withPrintWriter(file) { writer => writer.println(new java.util.Date) }

9.5 By-name parameters


withPrintWriter(file) { writer => writer.println(new java.util.Date) }
// In file control-abstraction/Assert.scala var assertionsEnabled = true def myAssert(predicate: () => Boolean) = if assertionsEnabled && !predicate() then throw new AssertionError
myAssert(() => 5 > 3)
myAssert(5 > 3) // Won't work, because missing () =>
// In file control-abstraction/Assert.scala def byNameAssert(predicate: => Boolean) = if assertionsEnabled && !predicate then throw new AssertionError
byNameAssert(5 > 3)
def boolAssert(predicate: Boolean) = if assertionsEnabled && !predicate then throw new AssertionError
boolAssert(5 > 3)
val x = 5 assertionsEnabled = false boolAssert(x / 0 == 0) java.lang.ArithmeticException: / by zero ... 27 elided
byNameAssert(x / 0 == 0) // Returns normally

9.6 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.