Search code examples
scalapackagescala-2.8

Confusion with a simple Scala packaging example


I've been experiencing confusion over packaging classes in Scala and importing packages. Let me start with a pair of simple source files:

file: a/A.scala

package a

// Which of these imports should be used? They both seem to work.
//import a.b._
import b._

class A {
   val fieldB = new B
}

file: a/b/B.scala

package a.b

class B

usage

Compiling with scalac works without complaint with either of the imports above in A.scala

Trying to load these files in the REPL works differently:

$ scala
Welcome to Scala version 2.8.0.r0-b20100714201327 (Java HotSpot(TM) Server VM, Java 1.6.0_20).
Type in expressions to have them evaluated.
Type :help for more information.

scala> :l a/b/B.scala
Loading a/b/B.scala...
<console>:1: error: illegal start of definition
       package a.b
       ^
defined class B

scala> :l a/A.scala
Loading a/A.scala...
<console>:1: error: illegal start of definition
       package a
       ^
<console>:5: error: not found: value b
       import b._
              ^
defined class A

scala>

So, I have a some questions:

  • What is the correct way to do that import in A.scala above?

  • The compiler seems to be able to figure out if an import is relative to the package we are in or if it is absolute, without the _root_. Is that what I'm seeing?

  • Am I doing this correctly in the REPL? Why does it seem so unhappy with seeing package statements, and why does the import b._ generate an error?

Thank you

PS I know the directory structure doesn't have to match the packaging. Doing so voluntarily is helping me to be less confused for now.


Solution

  • First off you cannot define packages in the REPL. The reason for this is that your REPL-statements are actually wrapped into objects. That's why your :load command fails. You would need to compile your source files and add it to the classpath if you want to use packages.

    When trying to resolve a symbol to be imported the compiler tries to find it in your actual scope, i.e. when you write

    import a._
    import b._
    

    this will import everything from package a and everything from package a.b. If you are inside package a then b is in your scope already and the second import is sufficient. The compiler also initially imports scala._ so you can also use relative imports like import xml._ to import scala.xml._.

    In addition there is a feature called nested packages which lets you write your B.scala like

    package a
    package b
    class B { /* .... */ }
    

    which results in everything from package a being imported in this file.

    If the compiler cannot resolve an import to a relative symbol it will look in the default package (_root_).