Scala: Reassignable variables and properties (def fields)

Sadly, I had to get away from Scala for a while, but now I can get back to it again. Just as I started getting back into it I happened upon the following code, and thought, “Well, surely title in this anonymous class is a var field. How strange that the Programming in Scala guys would use a var like this.”:

import scala.swing._

object FirstSwingApp extends SimpleGUIApplication {
    def top = new MainFrame {
        title = "First Swing App"  // <-- must be a 'var' field, right?
        contents = new Button {
            text = "Click me"
        }
    }
}

I love the syntax of being able to reassign title so easily, but a var? Surely there’s no way they did that.

Then I looked at the Scala Swing MainFrame Scaladoc, and saw that title is defined as a method (with def). “Well, what the heck,” I thought, “I’ve forgotten a lot of Scala, but I know that title can’t be a method. You’d have to override it like this if that was the case”:

def top = new MainFrame {
    override def title = "First Swing App"
    // ...
}

“How can this possibly work?”, I wondered.

Before reading on ...

Note: Before reading any further, it’s important to convince yourself that you either know how this code works, or, like me, you don’t know how it works:

def top = new MainFrame {
    title = "First Swing App"
    // ...
}

In this code you’re creating a new MainFrame instance using the anonymous class approach, and then the title “field” — which we now know is a def — is somehow being reassigned.

Solution

Long story short, I pulled the Programming in Scala book off the bookshelf, flipped to the “GUI Programming” chapter, scanned to page 759, and remembered how this works.

Somewhere in the Scala Swing class hierarchy there has to be some code that looked like this:

class MyMainFrame {
    def title: String = ???
    def title_=(s: String): Unit = ???
}

The key here is this line:

def title_=(s: String): Unit = ???

That method is actually a setter method for the title “attribute.”

As the book states, “In Scala’s Swing API, such attributes are modeled as properties. You know from Section 18.2 that properties are encoded in Scala as pairs of getter and setter methods.” They then show that this method is a getter:

def title: String = ???

and this method is a setter:

def title_=(s: String): Unit = ???

Using this approach is what lets you reassign title so conveniently:

def top = new MainFrame {
    title = "First Swing App"
    // ...
}

Note: The actual title methods are defined in the Scala Swing RichWindow class.

Proof

You can demonstrate for yourself that this approach works with the following example code:

object PropertiesTest extends App {

    def top = new MyMainFrame {
        title = "Hello, World!"
    }

}

class MyMainFrame {
    def title: String = "foo"
    def title_=(s: String): Unit = {}
}

If you copy and paste that code into your favorite IDE, you’ll see that the code compiles properly, but if you comment-out the setter method in MyMainFrame, you’ll see that the assignment to the title “field” no longer works.

More information

I’ll probably write more about this at some point, but until then, if you want to know more about how this works, please see Section 18.2 of Programming in Scala.