Code Examples for

Programming in Scala, Third Edition

Return to chapter index

29 Modular Programming Using Objects

Sample run of chapter's interpreter examples

29.1 The problem

29.2 A recipe application


// In file modular-programming-using-objects/Ex3.scala package org.stairwaybook.recipe abstract class Food(val name: String) { override def toString = name }
// In file modular-programming-using-objects/Ex3.scala package org.stairwaybook.recipe class Recipe( val name: String, val ingredients: List[Food], val instructions: String ) { override def toString = name }
// In file modular-programming-using-objects/Ex3.scala package org.stairwaybook.recipe object Apple extends Food("Apple") object Orange extends Food("Orange") object Cream extends Food("Cream") object Sugar extends Food("Sugar") object FruitSalad extends Recipe( "fruit salad", List(Apple, Orange, Cream, Sugar), "Stir it all together." )
// In file modular-programming-using-objects/Ex1.scala package org.stairwaybook.recipe object SimpleDatabase { def allFoods = List(Apple, Orange, Cream, Sugar) def foodNamed(name: String): Option[Food] = allFoods.find(_.name == name) def allRecipes: List[Recipe] = List(FruitSalad) } object SimpleBrowser { def recipesUsing(food: Food) = SimpleDatabase.allRecipes.filter(recipe => recipe.ingredients.contains(food)) }
scala> val apple = SimpleDatabase.foodNamed("Apple").get apple: Food = Apple scala> SimpleBrowser.recipesUsing(apple) res0: List[Recipe] = List(fruit salad)
// In file modular-programming-using-objects/Ex2.scala package org.stairwaybook.recipe object SimpleDatabase { def allFoods = List(Apple, Orange, Cream, Sugar) def foodNamed(name: String): Option[Food] = allFoods.find(_.name == name) def allRecipes: List[Recipe] = List(FruitSalad) case class FoodCategory(name: String, foods: List[Food]) private var categories = List( FoodCategory("fruits", List(Apple, Orange)), FoodCategory("misc", List(Cream, Sugar))) def allCategories = categories } object SimpleBrowser { def recipesUsing(food: Food) = SimpleDatabase.allRecipes.filter(recipe => recipe.ingredients.contains(food)) def displayCategory(category: SimpleDatabase.FoodCategory) = { println(category) } }

29.3 Abstraction


SimpleDatabase.allRecipes.filter(recipe => ...
// In file modular-programming-using-objects/Ex3.scala abstract class Browser { val database: Database def recipesUsing(food: Food) = database.allRecipes.filter(recipe => recipe.ingredients.contains(food)) def displayCategory(category: database.FoodCategory) = { println(category) } }
// In file modular-programming-using-objects/Ex3.scala abstract class Database { def allFoods: List[Food] def allRecipes: List[Recipe] def foodNamed(name: String) = allFoods.find(f => f.name == name) case class FoodCategory(name: String, foods: List[Food]) def allCategories: List[FoodCategory] }
// In file modular-programming-using-objects/Ex3.scala object SimpleDatabase extends Database { def allFoods = List(Apple, Orange, Cream, Sugar) def allRecipes: List[Recipe] = List(FruitSalad) private var categories = List( FoodCategory("fruits", List(Apple, Orange)), FoodCategory("misc", List(Cream, Sugar))) def allCategories = categories }
// In file modular-programming-using-objects/Ex3.scala object SimpleBrowser extends Browser { val database = SimpleDatabase }
scala> val apple = SimpleDatabase.foodNamed("Apple").get apple: Food = Apple scala> SimpleBrowser.recipesUsing(apple) res1: List[Recipe] = List(fruit salad)
// In file modular-programming-using-objects/Ex3.scala object StudentDatabase extends Database { object FrozenFood extends Food("FrozenFood") object HeatItUp extends Recipe( "heat it up", List(FrozenFood), "Microwave the 'food' for 10 minutes.") def allFoods = List(FrozenFood) def allRecipes = List(HeatItUp) def allCategories = List( FoodCategory("edible", List(FrozenFood))) } object StudentBrowser extends Browser { val database = StudentDatabase }

29.4 Splitting modules into traits


// In file modular-programming-using-objects/Ex4.scala trait FoodCategories { case class FoodCategory(name: String, foods: List[Food]) def allCategories: List[FoodCategory] }
// In file modular-programming-using-objects/Ex4.scala abstract class Database extends FoodCategories { def allFoods: List[Food] def allRecipes: List[Recipe] def foodNamed(name: String) = allFoods.find(f => f.name == name) }
// In file modular-programming-using-objects/Ex5.scala object SimpleDatabase extends Database with SimpleFoods with SimpleRecipes
// In file modular-programming-using-objects/SimpleFoods.scala trait SimpleFoods { object Pear extends Food("Pear") def allFoods = List(Apple, Pear) def allCategories = Nil }
trait SimpleRecipes { // Does not compile object FruitSalad extends Recipe( "fruit salad", List(Apple, Pear), // Uh oh "Mix it all together." ) def allRecipes = List(FruitSalad) }
// In file modular-programming-using-objects/SimpleRecipes.scala trait SimpleRecipes { this: SimpleFoods => object FruitSalad extends Recipe( "fruit salad", List(Apple, Pear), // Now Pear is in scope "Mix it all together." ) def allRecipes = List(FruitSalad) }

29.5 Runtime linking


// In file modular-programming-using-objects/GotApples.scala object GotApples { def main(args: Array[String]) = { val db: Database = if(args(0) == "student") StudentDatabase else SimpleDatabase object browser extends Browser { val database = db } val apple = SimpleDatabase.foodNamed("Apple").get for(recipe <- browser.recipesUsing(apple)) println(recipe) } }
$ scala GotApples simple fruit salad $ scala GotApples student $

29.6 Tracking module instances


scala> val category = StudentDatabase.allCategories.head category: StudentDatabase.FoodCategory = FoodCategory(edible,List(FrozenFood)) scala> SimpleBrowser.displayCategory(category) <console>:21: error: type mismatch; found : StudentDatabase.FoodCategory required: SimpleBrowser.database.FoodCategory SimpleBrowser.displayCategory(category) ^
// In file modular-programming-using-objects/GotApples2.scala object GotApples { // same definitions... for (category <- db.allCategories) browser.displayCategory(category) // ... } GotApples2.scala:14: error: type mismatch; found : db.FoodCategory required: browser.database.FoodCategory browser.displayCategory(category) ^ one error found
// In file modular-programming-using-objects/GotApples2.scala object browser extends Browser { val database: db.type = db }

29.7 Conclusion

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

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

and:

http://booksites.artima.com/programming_in_scala_3ed

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