Month: July 2011

Composition vs Inheritance: Converting Java’s Swing Timer class to Scala

Posted by – July 27, 2011

I’ve been having a look at using Swing in Scala. Java’s Swing is messy, verbose, buggy, and unintuitive. Scala sweetens things a bit, although if we’re to believe the rumours from the EPFL, the Observer Pattern, around which Swing is based, is more of an anti-pattern and should be deprecated. So maybe Swing’s days are numbered, but in the current absence of anything better, I’m diving in.

Scala has cleaned up some of the names and classes to make things a bit simpler, but there are some things missing, and Timer is one of them. This isn’t too much of a big deal, because you can still just use the Java version, but it would be nice if you could treat it in the same way as you do button clicks, using a Publisher / Reactor model, rather than Java’s Listeners (more details here).

So to bring up a Frame with a coloured background that changes according to a Timer, I did this:

import swing._
import java.awt.{Graphics, Color}
import java.awt.event.{ActionEvent, ActionListener}
import javax.swing.Timer

object ColorPanel extends SimpleSwingApplication {
  var c: Color = new Color(0)

  def top = new MainFrame {
    title = "Flash!"
    contents = p
  }

  val p = new Panel with ActionListener {
    preferredSize = new Dimension(200, 200)

    override def paintComponent(g: Graphics2D) {
      g.setColor(c)
      g.fillRect(0, 0, size.width, size.height)
    }

    def actionPerformed(e: ActionEvent) {
      c = new Color((c.getRGB() + 1000) % 16777216)
      repaint
    }
  }

  val timer = new Timer(100, p)
  timer.start()
}

That should be pretty simple to understand. Our application is a SimpleSwingApplication, which requires the top window to be specified in a method called top. We then define a Panel, and override the paintComponent method, just as in Java. We implement ActionListener‘s actionPerformed method, and here goes what we want the panel to do when it receives an event (i.e. change colour and repaint). Finally we specify the Timer and start it.

In Scala Swing, to react to an event, you listenTo a Publisher. So we want to make a Java Timer into a Publisher.

I started by making my ScalaTimer a Component, because you get Publisher / Reactor functionality for free. (This doesn’t really make sense, and actually all we need to do is to implement the Publisher trait.) The other way I thought of was to directly extend Java’s Timer class – although I wasn’t convinced this was the way, because the provided classes don’t seem to subclass their Java peers (they do some kind of wrapping with a peer value, which I don’t understand). Unsure which is best, I tried both.

1) Wrapping it (composition)

case class TimerEvent (source: AnyRef) extends swing.event.Event

class ScalaTimer(delayTime: Int) extends swing.Publisher {
  outer =>

  private val t = new javax.swing.Timer(delayTime, new java.awt.event.ActionListener {
    def actionPerformed(e: java.awt.event.ActionEvent) {
      publish(new TimerEvent(outer))
    }
  })

  def addActionListener(listener: java.awt.event.ActionListener) {t.addActionListener(listener)}
  def fireActionPerformed(e: swing.event.ActionEvent) {publish(e)}
  def actionCommand: String = t.getActionCommand
  def actionListeners: Array[ java.awt.event.ActionListener ] = t.getActionListeners
  def delay: Int = t.getDelay
  def initialDelay = t.getInitialDelay
  def listeners[A <: java.util.EventListener](listenerType: Class[A]) = t.getListeners(listenerType)
  def coalesce: Boolean = t.isCoalesce
  def repeats: Boolean = t.isRepeats
  def running: Boolean = t.isRunning
  def removeActionListener(listener: java.awt.event.ActionListener) {t.removeActionListener(listener)}
  def restart() {t.restart()}
  def actionCommand_=(command: String) {t.setActionCommand(command)}
  def coalesce_=(flag: Boolean) {t.setCoalesce(flag)}
  def delay_=(delay: Int) {t.setDelay(delay)}
  def initialDelay_=(initialDelay: Int) {t.setInitialDelay(initialDelay)}
  def repeats_=(flag: Boolean) {t.setRepeats(flag)}
  def start() {t.start()}
  def stop() {t.stop()}
}


object ScalaTimer {
  import javax.swing.Timer
  def getLogTimers: Boolean = Timer.getLogTimers
  def setLogTimers(flag: Boolean) {Timer.setLogTimers(flag)}
}

If that’s confusing, here are some explanations:

  • outer => is an alias which is a self-reference. It’s like this, except this isn’t always in scope, i.e. in inner classes, so we need to define an alias for the outer scope specifically
  • We instantiate a private Timer t, giving it an anonymous ActionListener, which publishes a TimerEvent whenever it gets an ActionEvent from t
  • We have to make our own Event type, because Scala’s ActionEvents require a Component to be specified as their source, and ScalaTimer isn’t a Component
  • I used fully qualified names to help avoid confusion, since there are both Scala and Java ActionEvents
  • I changed the method names to fit the Scala conventions, so instead of myTimer.getDelay(), we have myTimer.delay, and instead of myTimer.setRepeats(true), we state myTimer.repeats = true. Personally I think the _= syntactic sugar for setters can be confusing, since it’s syntactically the same as assigning a value to a field, so while you might think you’ve set a field to equal your object, it’s almost certainly done something else, like copying values.
  • We have a companion object at the end which allows us to include Timer’s static methods

Overall this was pretty straightforward, once I’d found out how to use aliases, although it involved quite a bit of typing, copying the methods from Timer’s javadoc.

2) Extending javax.swing.Timer (inheritance)

class ScalaTimer2 (delay: Int)
      extends Timer(delay, new ActionListener { def actionPerformed(e: ActionEvent) {} })
      with swing.Publisher {
  outer =>

  removeActionListener(getActionListeners.apply(0))

  addActionListener(new ActionListener {
    def actionPerformed(e: ActionEvent) {
      publish(new TimerEvent(outer))
    }
  })
}

object ScalaTimer2 {... same as ScalaTimer ...}

OK, this was a little tricky. Coming from a Java background, Scala’s constructors are a bit weird. If the base class constructor contains arguments, you have to pass these in your subclass signature, and the only values you have available are from the subclass’s arguments. Timer has only one constructor, which takes two arguments, an integer delay and an ActionListener. So we need to supply an ActionListener either by taking one in the main argument list, or generating one, as above.

Unfortunately neither a reference to self or the publish method will be available to pass in, because the object doesn’t yet exist. So above, we pass a dummy ActionListener which we then remove, then add a real one containing the publish method.

I also did a version using an auxiliary constructor taking just an Int, which I shortened to the above. Then I made the primary constructor private, similar to the example below.

Postscript: Actually it’s easier than this. The Timer you send to the Java constructor can be null. So all you need is:

class ScalaTimer2 (delay: Int) extends Timer(delay, null) with Publisher {
  outer =>
  addActionListener(new ActionListener {
    def actionPerformed(e: ActionEvent) {
      publish(new TimerEvent(outer))
    }
  })
}

Just add a companion object containing those pesky static methods, and that’s it!

3) Extending Timer, but using a factory method

Notice that adding a dummy ActionListener is a workaround rather than a solution, and in the general case, such methods won’t be available. Instead, we can avoid the constructor and use a factory method. Kipton Barros on StackOverflow showed me how to do this, using the companion object’s apply method, so a new timer can be invoked just like with a constructor, except without the new keyword.

class ScalaTimer3 private (delay: Int, listener: java.awt.event.ActionListener)
      extends javax.swing.Timer(delay, listener) with swing.Publisher {
  // no body!
}

object ScalaTimer3 {
  def apply(delay: Int): ScalaTimer3 = {
    lazy val ret: ScalaTimer3 = new ScalaTimer3(delay, new java.awt.event.ActionListener {
      def actionPerformed(e: java.awt.event.ActionEvent) {
        ret.publish(TimerEvent(ret))
      }
    })
    ret
  }
  // + static methods here
}

This cleverly uses a lazy val, which (for reasons not entirely understood) allows reference to itself within the inner class.

Note also I’ve added the private keyword to the primary constructor, so that only the object’s apply method is available.

Conclusion

So which solution is best? Well, given infinite time and patience, I would favour the first solution, where we compose rather than inherit. It’s the most flexible, and allowed us to alter the method names, and indeed change method implementation where desirable (as you might notice I did with the fireActionPerformed method, taking a Scala ActionEvent rather than a Java one). I don’t really expect these precise challenges with the constructors to come up often, but it was an instructive exercise. Oh, and here’s the ColorPanel example updated with the new Timer:

import swing._
import java.awt.Color

object ColorPanel extends SimpleSwingApplication {

  def top = new MainFrame {
    title = "Flash!"
    contents = p
  }

  val timer = new ScalaTimer(100)

  val p = new Panel {
    var c: Color = new Color(0)
    preferredSize = new Dimension(200, 200)
    listenTo(timer)
    reactions += {
      case e: TimerEvent => {
        c = new Color((c.getRGB + 1000) % 16777216)
        repaint
      }
    }

    override def paintComponent(g: Graphics2D) {
      g.setColor(c)
      g.fillRect(0, 0, size.width, size.height)
    }
  }

  timer.start()
}

Garbage collection in Java while references still exist

Posted by – July 24, 2011

Who would have thought it, my first meaningful post is on garbage collection!

There’s a common misconception that objects can only be garbage-collected when there no longer exist any references to those objects. Actually, HotSpot goes one better, and garbage collects when it determines you’re not going to use those references again. Which might be in the middle of a method while your variables are still theoretically in scope.

Here’s how I know this? I’m unable to concentrate long enough to read any actual documentation on the garbage collector, but I found some surprising results from this experiment, which simply attemepts to add 17 million Foos to a list 4 times, catches out of memory errors, and prints its results:

import java.util.ArrayList;
import java.util.List;

public class Foo {

    public static void main(String[] args) {
        test1();
        test2();
    }

    static void test1() {
        List<Foo> a = new ArrayList<Foo>();
        try {
            for (int i = 0; i < 17000000; i++) {
                a.add(new Foo());
            }
        } catch (OutOfMemoryError e) {
            System.out.println("a: out of memory");
        }
        System.out.println("Created " + a.size() + " foos");
        
        List<Foo> b = new ArrayList<Foo>();
        try {
            for (int i = 0; i < 17000000; i++) {
                b.add(new Foo());
            }
        } catch (OutOfMemoryError e) {
            System.out.println("b: out of memory");
        }
        System.out.println("Created " + b.size() + " foos");
    }

    static void test2() {
        List<Foo> a = new ArrayList<Foo>();
        try {
            for (int i = 0; i < 17000000; i++) {
                a.add(new Foo());
            }
        } catch (OutOfMemoryError e) {
            System.out.println("a: out of memory");
        }
        System.out.println("Created " + a.size() + " foos");
        
        List<Foo> b = new ArrayList<Foo>();
        try {
            for (int i = 0; i < 17000000; i++) {
                b.add(new Foo());
            }
        } catch (OutOfMemoryError e) {
            System.out.println("b: out of memory");
        }
        System.out.println("Created " + b.size() + " foos");
        a.size(); // <-- IMPORTANT: REFERENCE TO a
    }
}

In test1() we get the results
Created 17000000 foos
Created 17000000 foos

indicating that there was sufficient memory to create a second list of 17000000 Foos.
In test2() we get
Created 17000000 foos
b: out of memory
Created 3392918 foos

The only difference is that in test2(), we needed to keep hold of List a, in order to evaluate a.size() at the end. And we ran out of memory, which indicates the memory must have been freed during the method in test1().

Welcome

Posted by – July 17, 2011

It is with great pleasure that I announce the launch of LuigiP.com!

Please be sure to check back in the future, when there is some content!