Alex headshot

AlBlue’s Blog

Macs, Modularity and More

Introduction to Scala – dealing with objects

2007, howto, scala

In the previous post, I discussed functions in Scala. There's a lot more power and flexibility to come, but for now let's expose a little at a time. In this post, we'll look at the way in which we can integrate with Java objects.

Given that Scala runs inside a JVM, it's possible to interact with Java's types. For example, we can pull a list of system properties trivially in Scala by using the same code as we could in Java:

scala> val properties = System.getProperties()
properties: java.util.Properties = {java.runtime.name=Java(TM) 2 Runtime Environment, ...
scala> properties.get("user.name")
res1: java.lang.Object = alblue
scala> properties.size()
res2: Int = 55

It's easy enough to refer to methods of objects; it uses the same Java syntax to call methods with '.' — but there are some differences. For example, Scala doesn't have to supply the () for empty method calls:

scala> val properties = System.getProperties
properties: java.util.Properties = ...
scala> properties.size
res3: Int = 55

For that matter, you don't even need to use the '.' to call methods; you can use spaces:

scala> System getProperties
properties: java.util.Properties = ...
scala> properties get "user.name"
res4: java.lang.Object = alblue
scala> properties size
res5: Int = 55

If you're coming from an existing programming language that likes decorating the source code with punctuation, feel free to use it. Until you get comfortable with the syntax, it's possibly easier to use that form. To avoid confusion, I'll try and decorate the calls with syntax although in practice I rarely use it (so I might miss some places).

So, System is a reference to a Java class (java.lang.System) and we can invoke static methods. We've also seen how we can get an instance of another class (with getProperties()) and invoke instance methods. This is much like how Java deals with method invocation; and in fact, one of Scala's key benefits is to be able to quickly manipulate and process Java systems, much like you can with JRuby, JPython or even Groovy.

If we want, we can import static methods in the System class, which makes them available without having to prefix calls with System:

scala> import System.getProperties
import System.getProperties
scala> getProperties()
res6: java.util.Properties: {java.runtime.name=...

If we wanted to import everything in System, we'd use the wildcard. Unlike Java and C based languages, the wildcard in Scala is an underscore (_), a convention from other languages like Prolog and ML. (In those languages, it's supposed to represent a 'hole', like a fill-in-the-blanks space, and can match against anything. Don't worry too much about it, and mentally translate _ to * until you get used to it.) We can now use other System methods like getProperty:

scala> import System._
import System._
scala> getProperty("user.name")
res7: java.lang.String = alblue

What if we want to use a method, but by a different name? We can do that by creating a mapping of old names and new names in the import statement:

scala> import System.{getProperty => property, getProperties => properties}
import System.{getProperty=>property, getProperties=>properties}
scala> property("user.name")
res8: java.lang.String = alblue

In the syntax for the mapping we have here, we're using => in order to define the mapped values. This is a common operator in Scala, but rather than thinking of it as 'equal greater' (or confusing it with the greater-than-or-equal operator >=) it helps to translate it mentally to 'leads to' or 'goes to' or even just 'arrow'. It's an ASCII equivalent of a fairly standard math symbol (⇒).

Creating new instances is easy; we just use the new operator, as we would in Java:

scala> new java.net.URL("http://localhost")
res9: java.util.URL = http://localhost

The import is used to import classes from a package, much like Java does, and also like Java, you can import either a single class or everything:

scala> import java.net.URL
import java.net.URL
scala> new URL("http://localhost")
res10: new java.net.URL = http://localhost
scala> import java.util._
import java.util._

So, if we can import a class method under a new name, and it's the same import style as for importing classes from a package, can we do the same here?

scala> import java.net.{URL => UniformResourceLocator}
import java.net.{URL=>UniformResourceLocator}
scala> new UniformResourceLocator("http://localhost")
res11: java.net.URL = http://localhost
scala> import java.awt.{Color => Colour}
import java.awt.{Color=>Colour}

Now you can finally fix all those annoying typos in the Java language! Mind you, there are also valid times when you'd want to do this; if you want to (statically) enable or disable some logging or security component, you might want to use this to define a pseudo-type Factory and then alias it to LoggingFactory or SecureFactory.

The imports are valid until the end of the block that defines them (or the end of the file). In the interpreter, they last until the end of the session. If you want, you can define imports inside class definitions or even in individual function blocks. It's possible to define multiple imports on the same line by comma separating the imports, or you can have them on several lines; but that doesn't work in the interpreter.

Armed with the ability to use and instantiate simple Java objects, we'll leave this post here; next time, we'll be looking at how to create objects in Scala.