Scala for the Impatient

OOP2: Packages, Inheritance, and Traits

Copyright © Cay S. Horstmann 2015

Understand packages and package nesting

Packages

Packages

Work with import statements

Imports

Imports 2

Package Nesting

Declare subclasses and traits

Inheritance

Traits L1

Understand mixins and layered traits

Mixins

Layers

Practice working with traits

Lab

Scary looking lab

Part 1: Mixing in Missing Methods

  1. The java.awt.Rectangle class has a method translate that moves a rectangle by a given amount. Try it out: In a worksheet, import the java.awt package, construct a new Rectangle(5, 10, 20, 30), call translate(10, 20), and see what its coordinates are now.
  2. To make ellipses, you use the class java.awt.geom.Ellipse2D.Double. Make an instance val egg = new geom.Ellipse2D.Double(5, 10, 20, 30). Why didn't you have to put java.awt before geom?
  3. Now call egg.translate(10, 20). What happens?
  4. That's eggsasperating. Why didn't they add the method to Ellipse2D, or better, its superclass RectangularShape? We can fix that in Scala. Define a trait:
    trait RectangleLike {
        def setFrame(x: Double, y: Double, w: Double, h: Double): Unit
        def getX: Double
        def getY: Double
        def getWidth: Double
        def getHeight: Double
        def translate(dx: Double, dy: Double) { setFrame(getX + dx, getY + dy, getWidth, getHeight) }
      }
    
    Now change the definition of egg so that the call to translate works. What did you do?

Part 2: Reversing the Mixin Order

  1. Run through the “Layers” example and reverse the order of the mixins:
    val acct2 = new SavingsAccount
      with ConsoleLogger with ShortLogger with TimestampLogger {
      override val maxLength = 20
    }
    Without running the program, what do you think will happen when you call acct2.withdraw(1000)?
  2. Now run the program. Were you right?
  3. What happens when you try the following?
    val acct3 = new SavingsAccount
      with ShortLogger with TimestampLogger with ConsoleLogger 
    

Part 3: Buffering

  1. In the java.io library, one has to work hard to get services such as buffering:
    new BufferedReader(new InputStreamReader(new FileInputStream("/usr/share/dict/words")))
    It shouldn't be so hard to add buffering. (Buffering means not to read each byte separately but to read them a chunk at a time.) Here is a Scala trait:
    trait Buffered extends InputStream {
         val SIZE = 1024
         private var end = 0
         private val buffer = new Array[Byte](SIZE)
         private var pos = 0
         
         override def read() = {
           if (pos == end) {
             end = super.read(buffer, 0, SIZE)
             pos = 0
           }
           if (pos == end) -1 else {
             pos += 1
             buffer(pos - 1)
           }
         }
      }
    
    Mix in Buffered into a new FileInputStream("/usr/share/dict/words") (or some other file if you aren't running Linux/Mac OS). How do you do that? Then call read a few times. What do you get?
  2. How can you tell that buffering happens? Mix in a logger!