Code Examples for

Programming in Scala

Return to chapter index

27 Modular Programming Using Objects

Sample run of chapter's interpreter examples

27.1 The problem

27.2 A recipe application


// In file modules/Food.scala package org.stairwaybook.recipe abstract class Food(val name: String) { override def toString = name }
// In file modules/Recipe.scala package org.stairwaybook.recipe class Recipe( val name: String, val ingredients: List[Food], val instructions: String ) { override def toString = name }
// In file modules/Foods.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 modules/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 modules/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) } }

27.3 Abstraction


SimpleDatabase.allRecipes.filter(recipe => ...
// In file modules/Ex5.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 modules/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 modules/Ex4.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 modules/SimpleBrowser.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 modules/StudentDatabase.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 }

27.4 Splitting modules into traits


// In file modules/FoodCategories.scala trait FoodCategories { case class FoodCategory(name: String, foods: List[Food]) def allCategories: List[FoodCategory] }
// In file modules/Ex5.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 modules/SimpleDatabase.scala object SimpleDatabase extends Database with SimpleFoods with SimpleRecipes
// In file modules/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 modules/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) }

27.5 Runtime linking


// In file modules/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 $

27.6 Tracking module instances


scala> val category = StudentDatabase.allCategories.head category: StudentDatabase.FoodCategory = FoodCategory(edible,List(FrozenFood)) scala> SimpleBrowser.displayCategory(category) <console>:12: error: type mismatch; found : StudentDatabase.FoodCategory required: SimpleBrowser.database.FoodCategory SimpleBrowser.displayCategory(category) ^
// In file modules/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 modules/GotApples2.scala object browser extends Browser { val database: db.type = db }

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