Code Examples for

Programming in Scala

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) if (num < 0) exists = true exists }
scala> containsNeg(List(1, 2, 3, 4)) res0: Boolean = false scala> containsNeg(List(1, 2, -3, 4)) res1: Boolean = true
def containsNeg(nums: List[Int]) = nums.exists(_ < 0)
scala> containsNeg(Nil) res2: Boolean = false scala> containsNeg(List(0, -1, -2)) res3: Boolean = true
def containsOdd(nums: List[Int]): Boolean = { var exists = false for (num <- nums) if (num % 2 == 1) exists = true exists }
def containsOdd(nums: List[Int]) = nums.exists(_ % 2 == 1)

9.3 Currying


scala> def plainOldSum(x: Int, y: Int) = x + y plainOldSum: (Int,Int)Int scala> plainOldSum(1, 2) res4: Int = 3
scala> def curriedSum(x: Int)(y: Int) = x + y curriedSum: (Int)(Int)Int scala> curriedSum(1)(2) res5: Int = 3
scala> def first(x: Int) = (y: Int) => x + y first: (Int)(Int) => Int
scala> val second = first(1) second: (Int) => Int = <function>
scala> second(2) res6: Int = 3
scala> val onePlus = curriedSum(1)_ onePlus: (Int) => Int = <function>
scala> onePlus(2) res7: Int = 3
scala> val twoPlus = curriedSum(2)_ twoPlus: (Int) => Int = <function> scala> twoPlus(2) res8: Int = 4

9.4 Writing new control structures


scala> def twice(op: Double => Double, x: Double) = op(op(x)) twice: ((Double) => Double,Double)Double scala> twice(_ + 1, 5) res9: Double = 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) )
scala> println("Hello, world!") Hello, world!
scala> println { "Hello, world!" } Hello, world!
scala> val g = "Hello, world!" g: java.lang.String = Hello, world! scala> g.substring { 7, 9 } <console>:1: error: ';' expected but ',' found. g.substring { 7, 9 } ^
scala> g.substring(7, 9) res12: java.lang.String = 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()) 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) throw new AssertionError
byNameAssert(5 > 3)
def boolAssert(predicate: Boolean) = if (assertionsEnabled && !predicate) throw new AssertionError
boolAssert(5 > 3)
scala> var assertionsEnabled = false assertionsEnabled: Boolean = false scala> boolAssert(x / 0 == 0) java.lang.ArithmeticException: / by zero at .<init>(<console>:8) at .<clinit>(<console>) at RequestResult$.<init>(<console>:3) at RequestResult$.<clinit>(<console>)...
scala> byNameAssert(x / 0 == 0)

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