Mike Slinn

Scala Imports and Packages

— Draft —

Published 2013-12-29. Last modified 2016-02-05.
Time to read: 5 minutes.

This lecture discusses Scala’s imports and package concepts.

Like Java, source files can be grouped into packages. Unlike Java, the directory structure is decoupled from the Scala packages. Furthermore, you can scope a package, so that only a portion of a source file resides within a package. Here is a sample file, called TemporalSpatial.scala. Two classes are defined: com.micronautics.Temporal and com.micronautics.alternate.Spatial. These classes are all provided in the courseNotes SBT project.

Scala code
package com.micronautics
class Temporal
package alternate { class Spatial { println(s"Spatial’s constructor says that doubling 21 gives ${doubler(21)}") } }

Just to make a point, the file above is in the a/b/c source directory. The point I am making is that the organization on disk is quite unrelated to the package statements. You can put all your classes in the same directory, even if they declare different packages, or you can put them in completely random directories. I do not recommend this, but it is possible. The Scala compiler only looks at the package statements to determine the package structure of your code.

Package Objects and package.scala

Scala 2 had package objects, which can contain package-level definitions. Scala 3 dropped package objects, so if you are only interested in Scala 3 you can skip this section.

Scala 2 code
package object bar {
  ...
}

... is just syntactic sugar for:

Equivalent Scala 2 code
package bar {
    object `package` {
      ...
  }
}

Usually package objects just define methods, properties and implicits, as well as package-level documentation in package objects. Looking ahead to the lectures on implicits of the Intermediate Scala course (Implicit Values, Implicit Conversions, and Implicit Classes), you could mix in traits that define implicits into the package object to make the implicits available any time the package is imported. We’ll see examples of how that works in the Intermediate Scala course.

Package-level documentation should provide an overview of the major classes, with some basic examples of how to use the classes in that package.

By convention, package objects are frequently defined in a file called package.scala, however this is not a requirement. You can place package objects in any file with a .scala filetype.

Here is an example of a package object which I have placed in package.scala in the courseNotes project. Notice that the doubler method is defined within a package object for the package com.micronautics.alternate. You can invoke doubler from anywhere in the com.micronautics.alternate package without qualification because package objects are automatically imported into the package of the same name. This is actually done in the constructor for class Spatial, which evaluates doubler(21) and prints the result. Notice that I referenced classes in the Scaladoc using square-bracket notation.

Scala 2 code
/** Provides classes for whatever it is that this package does.
* Also provides implicits related to this class.
*
* ==Overview==
* The main class to use is [[com.micronautics.Whatever]].
* {{{
* scala> doubler(3)
* res0: Int = 6
* }}} */
package object alternate {
  def doubler(x: Int): Int = x * 2
}

Here is an entry point for a console application that exercises the classes above, rather like how Java’s static main method works:

Scala 2 code
object PackageDemo extends App {
  val ceeABC = new com.micronautics.Temporal
  val ceeXYZ = new com.micronautics.alternate.Spatial
}

We can run the above Scala 2 code from the command line as follows:

Shell
$ sbt "run-main PackageDemo"
[info] Loading global plugins from /home/mslinn/.sbt/0.13/plugins
[info] Loading project definition from /var/work/course_scala_intro_code/courseNotes/project
[info] Updating {file:/var/work/course_scala_intro_code/courseNotes/project/}coursenotes-build...
[info] Resolving org.fusesource.jansi#jansi;1.4 ...
[info] Done updating.
[info] Set current project to scalaIntroCourse (in build file:/var/work/course_scala_intro_code/courseNotes/)
Spatial’s constructor says that doubling 21 gives 42
[success] Total time: 7 s, completed Dec 17, 2013 10:17:19 PM 

Packages in the REPL

Prior to Scala 2.11, package statements could not be entered in the REPL. Since then, you still cannot use a package statement in the REPL without doing the proper dance.

Scala 2 REPL
scala> package x
<console>:1: error: illegal start of definition
       package x
scala>
package { val x = 0 } <console>:1: error: illegal start of definition package { val x = 0 }
scala>
package object { val x = 0 } <console>:1: error: illegal start of definition package object { val x = 0 }

Scala 2.11 introduced a new dance partner, :paste -raw, which allows defining packages in the REPL. Without this, you cannot access artifacts from the REPL in other packages that have restricted visibility. We will learn more about access modifiers and visibility in the Deceptively Familiar: Access Modifiers lecture.

Scala 2 and Scala 3 REPLs
scala> :paste -raw
// Entering paste mode (ctrl-D to finish)
package foo class Bar ^D // Exiting paste mode, now interpreting.

Now you can create instances:

Scala 2 and Scala 3 REPLs (continued)
scala> new foo.Bar
res2: foo.Bar = foo.Bar@10289886
scala>
import foo.Bar import foo.Bar
scala>
new Bar res3: foo.Bar = foo.Bar@2d1dee39

You can define classes, traits and objects.

Scala 2 and Scala 3 REPLs (continued)
scala> :paste -raw
// Entering paste mode (ctrl-D to finish)
package y object z { val a = 0 } ^D // Exiting paste mode, now interpreting.
scala>
y.z res5: y.z.type = y.z$@56193c7d

:paste -raw Limitations

You cannot define top-level variables using:paste -raw:

Scala REPL showing error
scala> :paste -raw
// Entering paste mode (ctrl-D to finish)
package x val a = 0 ^D // Exiting paste mode, now interpreting.
<pastie>:2: error: expected class or object definition val a = 0 ^ There were compilation errors!

It does not matter if you try to define a top-level variable or method after a package statement or within a scoped package, like this:

Scala REPL showing error
scala> :paste -raw
// Entering paste mode (ctrl-D to finish)
package x { val x = 0 } ^D // Exiting paste mode, now interpreting.
<pastie>:2: error: expected class or object definition val x = 0 ^ There were compilation errors!

Handy Trick for Scala 2 Only

Because Scala 3 removed package objects, this trick only applies to Scala 2.

You can escape Scala keywords by enclosing them in `backticks`. This allows us to nest an object named package inside another package – effectively defining a package object for the current package scope. In this example, I define a variable called theNextAnswer in the package object for package a.b.c.

Scala REPL
package a.b.c
/** Here is some package-level documentation */ object `package` { val theNextAnswer = 43 }

Code Review Fail

You can escape any Scala keyword in backticks, allowing you to define a variable called match, a method called def, a class called package, etc. Please do not use this feature unless it is absolutely necessary! Here is some confusing code that should get you fired after a code review:

Scala code
abstract class `class`(`match`: String) {
  def `def` = `match` match {
    case "three" => 3
    case _ => Unit
  }
}

Following is another example of abusing backticks. The new class defines a parametric method called new. We will discuss parametrics in the Parametric Types lecture of the Intermediate Scala course.

Scala REPL
scala> class `new` { def `new`[`new`](`new`: `new`): `new` = `new` }
defined class new
scala>
new `new`().`new`(new `new`) res0: new = new@1a891add

import Statements

Import statements can reference specific classes:

Scala code
import scala.collection.immutable.List

... or several classes:

Scala code
import scala.collection.immutable.{List, Seq, Map}

... or all classes in a package (the underscore is often used as a wildcard in Scala):

Scala code
import scala.collection.immutable._

The scala package name can be omitted if there is no ambiguity with other packages of the same name.

Scala code
import collection.immutable.List

Classes and packages can be renamed. Here we rename the Java List to JList, so the Scala List can also be imported without a naming conflict.

Scala code
import java.util.{ List => JList }
import collection.{ immutable => cim }
import cim.List

You can also hide imported class names by renaming them to underscore (_).

As Yoda said, there is no Try, there is only Do, or DoNot. The Yoda He Is exercise in the Try and try/catch/finally lecture will have you work through this intriguing Scala code.

Scala code
import scala.util.{Try => _, Success => Do, Failure => DoNot}

Locally Scoped imports

Unlike Java, where import statements are all placed at the top of source files, import statements in Scala should be located in the most local scope practical.

The sample code for this lecture can be found in courseNotes/src/main/scala/TimedTask.scala.

The following code is an example of how Scala can be used to extend Java’s capabilities.

Scala code
object TimedTask {
  import java.util.{Timer, TimerTask}
def apply(intervalSeconds: Int=1)(op: => Unit): Unit = { val task = new TimerTask { def run = op } val timer = new Timer timer.schedule(task, 0L, intervalSeconds*1000L) } }
object TimedDemo extends App { import java.util.Date
TimedTask(1)(println(s"Hello, world! ${new Date}")) }

The TimedTask.apply method above accepts two parameters: the number of seconds between invocations of a closure (intervalSeconds), and a closure (op) to run periodically. I am not going to explain the rest of this program right now, I just want you to see how the import statements have been scoped within objects. The Closures lecture later in this course will explain what a closure is.

We can run the TimedDemo entry point at a console prompt with:

Shell
scala> sbt ~"runMain TimedDemo"
Loading /usr/share/sbt/bin/sbt-launch-lib.bash
[info] Loading global plugins from /home/mslinn/.sbt/0.13/plugins
[info] Loading project definition from /var/work/course_scala_intro_code/courseNotes/project
[info] Set current project to scalaIntroCourse (in build file:/var/work/course_scala_intro_code/courseNotes/)
Hello, world! Sun Dec 29 10:30:51 PST 2013
Hello, world! Sun Dec 29 10:30:52 PST 2013
Hello, world! Sun Dec 29 10:30:53 PST 2013
Hello, world! Sun Dec 29 10:30:54 PST 2013
Hello, world! Sun Dec 29 10:30:55 PST 2013
Hello, world! Sun Dec 29 10:30:56 PST 2013 
^C

imports Can Enable Advanced Scala Language Features

The scala.language object controls the language features available to the programmer. Each of these features has to be explicitly imported into the current scope to become available. In this way an organization can control the nature of the Scala code that is written, by mandating or disallowing these imports.

Scala code
import scala.language.postfixOps
List(1, 2, 3) reverse

To enable all language features:

Scala code
import scala.language._

The language features that can be enabled are:

  • dynamics adds developer driven dynamic binding (dynamic dispatch) and gives a subset of the features of dynamic typing to Scala, via the Dynamic trait. This feature is not described further in this course.
  • postfixOps enables postfix operators. This feature enables an alternative writing style, which may be more natural in some circumstances, and is described this course.
  • reflectiveCalls enables structural types. This feature is described in detail in the Intermediate Scala course.
  • implicitConversions enables defining implicit methods and members. This feature is described in detail in the Intermediate Scala course.
  • higherKinds enables writing higher-kinded types.
  • existentials enables writing existential types.
  • experimental contains newer features that have not yet been tested in production and may be significantly changed or removed in future versions of Scala. The only features in the experimental category of Scala version 2.13 is the macro capability. This feature is not described in this course; the Scala macro facility completely changed for Scala 3.

* indicates a required field.

Please select the following to receive Mike Slinn’s newsletter:

You can unsubscribe at any time by clicking the link in the footer of emails.

Mike Slinn uses Mailchimp as his marketing platform. By clicking below to subscribe, you acknowledge that your information will be transferred to Mailchimp for processing. Learn more about Mailchimp’s privacy practices.