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 ofbar
orbaz
. - 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
andbaz
.
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.
this post is sponsored by my books: | |||
#1 New Release |
FP Best Seller |
Learn Scala 3 |
Learn FP Fast |