How to use import statements anywhere (methods, blocks) in Scala

This is an excerpt from the Scala Cookbook (partially modified for the internet). This is Recipe 7.6, “How to use import statements anywhere (methods, blocks) in Scala.”

Problem

You want to use an import statement anywhere in your Scala code, generally to limit the scope of the import, to make the code more clear, or to organize your code.

Solution

You can place an import statement almost anywhere inside a program. As with Java, you can import members at the top of a class definition, and then use the imported resource later in your code:

package foo

import scala.util.Random

class ImportTests {
    def printRandom {
        val r = new Random
    }
}

You can import members inside a class:

package foo

class ImportTests {
    import scala.util.Random
    def printRandom {
        val r = new Random
    }
}

This limits the scope of the import to the code in the class that comes after the import statement.

You can limit the scope of an import to a method:

def getRandomWaitTimeInMinutes: Int = {
    import com.alvinalexander.pandorasbox._
    val p = new Pandora
    p.release
}

You can even place an import statement inside a block, limiting the scope of the import to only the code that follows the statement, inside that block. In the following example, the field r1 is declared correctly, because it’s within the block and after the import statement, but the declaration for field r2 won’t compile, because the Random class is not in scope at that point:

def printRandom {
    {
        import scala.util.Random
        val r1 = new Random   // this works
    }
    val r2 = new Random     // error: not found: type Random
}

Discussion

Import statements are read in the order of the file, so where you place them in a file also limits their scope. The following code won’t compile because I attempt to reference the Random class before the import statement is declared:

// this doesn't work because the import is after the attempted reference
class ImportTests {
    def printRandom {
        val r = new Random   // fails
    }
}

import scala.util.Random

When you want to include multiple classes and packages in one file, you can combine import statements and the curly brace packaging approach to limit the scope of the import statements, as shown in these examples:

package orderentry {
    import foo._
    // more code here ...
}

package customers {
    import bar._
    // more code here ...
    package database {
        import baz._
        // more code here ...
    }
}

In this example, members can be accessed as follows:

  • Code in the orderentry package can access members of foo, but can’t access members of bar or baz.
  • Code in customers and customers.database can’t access members of foo.
  • Code in customers can access members of bar.
  • Code in customers.database can access members in bar and baz.

The same concept applies when defining multiple classes in one file:

package foo

// available to all classes defined below
import java.io.File
import java.io.PrintWriter

class Foo {
    // only available inside this class
    import javax.swing.JFrame
    // ...
}

class Bar {
    // only available inside this class
    import scala.util.Random
    // ...
}

Although placing import statements at the top of a file or just before they’re used can be a matter of style, I find this flexibility to be useful when placing multiple classes or packages in one file. In these cases, it’s nice to keep the imports in a small scope to limit namespace issues, and also to make the code easier to refactor as it grows.