But no excuses! Let's have a look at some specific Scala code and see what we can figure out in general from it.
Today's snippet of Scala code is brought to you by
net.liftweb.util.Helpers.scala
, for those of you following along in the book. I've elided a lot of it, for the purposes of this post. Here are the relevant lines of code, suitable for entering into your scala
interpreter:
import java.text.SimpleDateFormat
import java.util.TimeZone
val utc = TimeZone.getTimeZone("UTC")
def internetDateFormatter = {
val ret = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss z")
ret.setTimeZone(utc)
ret
}
Besides the lack of semicolons (yea!) and the use of some standard Java classes (likewise yea!), one of the first things to notice is that
utc
is declared as a val
, while internetDateFormatter
is declared as a def
. You can probably intuit the difference, but we'll see some examples in a moment of just how they're different. Also, notice that neither utc
nor internetDateFormatter
is given an explicit type. Each has a specific type, determined by the type of what's on the right hand of the assignment, but the compiler doesn't need to see the type declared on the left hand side. This has some consequences that we'll see too.Finally, the definition of
internetDateFormatter
ends simply with the line ret
. This idiom will be familiar to the Ruby programmers in the audience, as it simply declares what the ultimate value is of the block that constitutes the right hand side of the assignment to the variable internetDateFormatter
. That is, in Scala, as in Ruby, the value of a block is the value of the last statement executed within the block.Try entering the above code, line by line, in a
scala
interpreter. The imports aren't that interesting, but notice what you get as a result of entering the declaration of utc
:
scala> val utc = TimeZone.getTimeZone("UTC")
utc: java.util.TimeZone = sun.util.calendar.ZoneInfo[id="UTC",
offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null]
Which says that
utc
is of type java.util.TimeZone
, and in particular it is equal to a sun.util.calendar.ZoneInfo
with the corresponding id, offset, etc. Whereas when you finish declaring internetDateFormatter
, you simply get:
scala> def internetDateFormatter = {
| val ret = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss z")
| ret.setTimeZone(utc)
| ret
| }
internetDateFormatter: java.text.SimpleDateFormat
Now you can start using
internetDateFormatter
as you would any instance of SimpleDateFormat
. For example:
scala> internetDateFormatter.toPattern()
res8: java.lang.String = EEE, d MMM yyyy HH:mm:ss z
Even more fun is this: now you have a result (
res8
, or whatever pops up for you), which is a java.lang.String
, and can be treated as such:
scala> res8.split("\\s")
res9: Array[java.lang.String] = [Ljava.lang.String;@66718
scala> res9.toString()
res10: String = Array(EEE,, d, MMM, yyyy, HH:mm:ss, z)
(Author's Note: Have you ever wanted an
irb
(the interactive ruby interpreter) for Java? Download Scala, and get one for free today!)So what about the difference between declaring with
val
and declaring with def
? Let's find out:
scala> utc = TimeZone.getTimeZone("GMT-7")
line19$object.$iw.$iw.utc = TimeZone.getTimeZone("GMT-7"):6: error: assignment to non-variable
val res12 = {utc = TimeZone.getTimeZone("GMT-7");utc}
^
Uh-oh. Looks like Scala considers
val
s to be constant. Although:
scala> val utc = TimeZone.getTimeZone("GMT-7")
utc: java.util.TimeZone = sun.util.calendar.ZoneInfo[id="GMT-07:00",offset=-25200000,dstSavings=0,useDaylight=false,transitions=0,lastRule=null]
It also looks like some constants are more constant than others. But before you start thinking you can just reassign
internetDateFormatter
with impunity:
scala> internetDateFormatter = "impunity":5: error: value internetDateFormatter_= is not a member of object $iw
val res13 = {internetDateFormatter = "impunity";internetDateFormatter}
^
Whatever that means. I'm going to have to track that one down and report on it later. Right now it's time for more life (read: "sleep") to intervene.