/* 22c22: Object Oriented Software Development Fall 2012 The University of Iowa Instructor: Cesare Tinelli */ /* Scala examples seen in class */ /* Singleton Classes */ // Scala has "singleton classes", classes containing exactly // one object // The syntax for defining such classes is // object { } // where // is any identifier and // is the same as in class definitions. object A { private val a = 1 val b = "abc" + a var c = 5 def f(x:Int) = x + 1 } // The definition above creates a class with a single instance with name A // In Scala such instances are called "objects" // The public fields and methods of an object can be used as // with any class instance A.a // error, a is private A.b A.c = 0 A.f(4) A f 4 // Singleton classes can inherit from other classes class Counter { protected var c = 0 def inc { c = c + 1 } def current = c } // Defines a sigleton subclass of Counter, whose only instance is C1 object C1 extends Counter C1.inc C1.current // Defines a sigleton subclass of Counter which extends Counter // with a decrement method, and whose only instance is called C2 object C2 extends Counter { def dec { c = c - 1 } } C2.inc C2.dec C2.current // Object can be used to create distinguished instances of classes // basic class for celestial body in astronomy class CelestialBody ( val mass: Double // body mass in kilograms ) // planet class class Planet (m: Double) extends CelestialBody(m) { } // satellite class class Satellite (m: Double, val planet: Planet) extends CelestialBody(m) { } // a particular planet, Earth, is defined as a singleton subclass of Planet object Earth extends Planet(5.9736e24) // a particular satellite, Earth's moon, is defined as a singleton subclass of Planet object Moon extends Satellite(7.347e22, Earth) // Note: strictly speaking Earth belongs to a subclass of Planet, but of course // it can be used anywhere a direct instance of Planet is used def printMass(p:Planet) { println("The planet's mass is " + p.mass) println } printMass(Earth) // A common use of objects is as modules // For instance, to collect together code in a single place // a programs that uses some global values could put them all together in a single // objects called Global object Globals { var check = true var limit = 1000 var greeting = "Hello" } // Objects are also used as entry points in a program // the Scala convention is to provide an object with method // called main with type (args: Array[String])Unit // running the programs starts with running the method main of the object // any input arguments for the program are passed to main, as strings, in the array // args in the order given object demo { val greetings = "Hello world" def main(args : Array[String]) : Unit = { println if (args.length == 0) printGreetings else println("Hello " + args(0)) println } def printGreetings { println(greetings) } } // Compiling a file demo.scala consisting of the object demo above with // // scalac demo.scala // // produces a JVM byte-code program called demo.class // // Running the program with // // scala demo // // results in the string "Hello world" being sent to the standard output // // Running the program with // // scala demo Joe // // results in the string "Hello Joe" being sent to the standard output /* Examples below adapted from Programming in Scala, Second Edition by Martin Odersky, Lex Spoon, and Bill Venners. Artima, 2010. */ // Packages :cp mypackages //----------------------------------- // In file mypackages/ex1.scala package rockets.navigation class Navigator //----------------------------------- import rockets._ val n1 = new navigation.Navigator import rockets.navigation._ val n2 = new Navigator //----------------------------------- // In file mypackages/ex2.scala package rockets2.navigation { class Navigator } //----------------------------------- import rockets2.navigation._ val n2 = new Navigator //--------------------------- // Imports //--------------------------- //------------------------------- // In file mypackages/fruits.scala package bobsdelights { abstract class Fruit( val name: String, val color: String ) object FruitBasket { object Apple extends Fruit("apple", "red") object Orange extends Fruit("orange", "orange") object Pear extends Fruit("pear", "yellowish") val menu = List(Apple, Orange, Pear) } } //------------------------------- object Kiwi extends bobsdelights.Fruit("kiwi", "green") // easy access to Fruit import bobsdelights.Fruit // easy access to all members of bobsdelights import bobsdelights._ // easy access to all members of FruitBasket import bobsdelights.FruitBasket._ // imports can be also dynamic def showFruit(fruit: Fruit) { import fruit._ println(name +"s are "+ color) } // Implicit imports import java.lang._ // everything in the java.lang package import scala._ // everything in the scala package import Predef._ // everything in the Predef object //----------------------------------- // In file mypackages/ex3.scala package rockets3 { package navigation { // In package rockets.navigation class Navigator package tests { // In package rockets.navigation.tests class NavigatorSuite } } } //----------------------------------- //----------------------------------- // In file mypackages/ex4.scala package rockets4 { // rockets.navigation package navigation { // rockets.navigation.Navigator class Navigator { // No need to say rockets.navigation.StarMap val map = new StarMap } // rockets.navigation.StarMap class StarMap } // rockets.Ship class Ship { // No need to say rockets.navigation.Navigator val nav = new navigation.Navigator } // rockets.fleets package fleets { // rockets.fleets.Fleet class Fleet { // No need to say rockets.Ship def addShip() { new Ship } } } } //----------------------------------- //--------------------------- package rockets { // rockets.Ship class Ship } package rockets.fleets { // rockets.fleets.Fleet class Fleet { // Doesn't compile! Ship is not in scope. def addShip() { new Ship } } } //------------------------------- // In file mypackages/launch.scala // In file launch.scala package launch { class Booster3 } // In file rockets.scala package rockets { package navigation { package launch { class Booster1 } class MissionControl { val booster1 = new launch.Booster1 val booster2 = new rockets.launch.Booster2 val booster3 = new _root_.launch.Booster3 } } package launch { class Booster2 } } //--------------------------- // Access modifiers // In file packages/Ex8.scala.err class Outer { class Inner { private def f() { println("f") } class InnerMost { f() // OK } } (new Inner).f() // error: f is not accessible } //--------------------------- // In file packages/Ex9.scala.err package p { class Super { protected def f() { println("f") } } class Sub extends Super { f() } class Other { (new Super).f() // error: f is not accessible } } //--------------------------- // In file packages/ex10/Ex10.scala package rockets package navigation { private[rockets] class Navigator { protected[navigation] def useStarChart() {} class LegOfJourney { private[Navigator] val distance = 100 } private[this] var speed = 200 } } package launch { import navigation._ object Vehicle { private[launch] val guide = new Navigator } } //--------------------------- val other = new Navigator other.speed // this line would not compile //--------------------------- // In file packages/Rocket.scala class Rocket { import Rocket.fuel private def canGoHomeAgain = fuel > 20 } object Rocket { private def fuel = 10 def chooseStrategy(rocket: Rocket) { if (rocket.canGoHomeAgain) goHome() else pickAStar() } def goHome() {} def pickAStar() {} } //--------------------------- // Package objects // In file packages/package.scala // In file bobsdelights/package.scala package object bobsdelights { def showFruit(fruit: Fruit) { import fruit._ println(name +"s are "+ color) } } // In file PrintMenu.scala package printmenu import bobsdelights.Fruits import bobsdelights.showFruit object PrintMenu { def main(args: Array[String]) { for (fruit <- Fruits.menu) { showFruit(fruit) } } }