Scala: How to declare a variable (var) before using it in try/catch/finally

This is an excerpt from the Scala Cookbook (partially modified for the internet). This is Recipe 3.17, “How to declare a variable (var) before using it in try/catch/finally.”

Problem

You want to use an object in a Scala try block, and need to access it in the finally portion of the block, such as when you need to call a close method on an object.

Solution

In general, declare your field as an Option before the try/catch block, then create a Some inside the try clause. This is shown in the following example, where the fields in and out are declared before the try/catch block, and assigned inside the try clause:

import java.io._

object CopyBytes extends App {
    var in = None: Option[FileInputStream]
    var out = None: Option[FileOutputStream]
    try {
        in = Some(new FileInputStream("/tmp/Test.class"))
        out = Some(new FileOutputStream("/tmp/Test.class.copy"))
        var c = 0
        while ({c = in.get.read; c != −1}) {
            out.get.write(c)
        }
    } catch {
        case e: IOException => e.printStackTrace
    } finally {
        println("entered finally ...")
        if (in.isDefined) in.get.close
        if (out.isDefined) out.get.close
    }
}

In this code, in and out are assigned to None before the try clause, and then reassigned to Some values inside the try clause if everything succeeds. Therefore, it’s safe to call in.get and out.get in the while loop, because if an exception had occurred, flow control would have switched to the catch clause, and then the finally clause before leaving the method.

Normally I tell people that I wish the get and isDefined methods on Option would be deprecated, but this is one of the few times where I think their use is acceptable, and they lead to more readable code.

Another approach you can employ inside the try clause is to use the foreach approach with a Some:

try {
    in = Some(new FileInputStream("/tmp/Test.class"))
    out = Some(new FileOutputStream("/tmp/Test.class.copy"))
    in.foreach { inputStream =>
        out.foreach { outputStream =>
            var c = 0
            while ({c = inputStream.read; c != −1}) {
                outputStream.write(c)
            }
        }
    }
} // ...

This is still readable with two variables, and eliminates the get method calls, but wouldn’t be practical with more variables.

Discussion

One key to this recipe is knowing the syntax for declaring Option fields that aren’t initially populated:

var in = None: Option[FileInputStream]
var out = None: Option[FileOutputStream]

I had a hard time remembering this until I came up with a little mnemonic, “Var x has No Option yeT,” where I capitalize the “T” there to stand for “type.” In my brain it looks like this:

var x has No Option[yeT]

From there it’s a simple matter to get to this:

var x = None: Option[Type]

When I first started working with Scala, the only way I could think to write this code was using null values. The following code demonstrates the approach I used in an application that checks my email accounts. The store and inbox fields in this code are declared as null fields that have the Store and Folder types (from the javax.mail package):

// (1) declare the null variables
var store: Store = null
var inbox: Folder = null
try {
    // (2) use the variables/fields in the try block
    store = session.getStore("imaps")
    inbox = getFolder(store, "INBOX")
    // rest of the code here ...
catch {
    case e: NoSuchProviderException => e.printStackTrace
    case me: MessagingException => me.printStackTrace
} 
finally {
    // (3) call close() on the objects in the finally clause
    if (inbox != null) inbox.close
    if (store != null) store.close
}

However, working in Scala gives you a chance to forget that null values even exist, so this is not a recommended approach. See Recipe 20.5, “Eliminate null Values from Your Code”, for examples of how to rid your code of null values.

See Also

  • The code shown in this recipe is a Scala version of this Oracle “Byte Streams” example