07. Packages and Imports - RobertMakyla/scalaWiki GitHub Wiki

KEY POINTS:

  • Packages nest just like inner classes.
  • Package paths are not absolute.
  • A chain x.y.z in a package clause leaves the intermediate both packages 'x' and 'x.y' invisible.
  • Package statements without braces at the top of the file extend to the entire file.
  • A package object can hold functions and variables.
  • Import statements can import packages, classes, and objects.
  • Import statements can be anywhere.
  • Import statements can rename and hide members.
  • java.lang, scala, and Predef are always imported.

Package Visibility

  • public - member not labeled private or protected is by default public
  • private - accessible for all instances of current class
  • protected - accessible only for all instances of current class and subclasses. Unlike in Java, it's not accessible in the package outside heritage tree
  • unlike Java, there's no fourth default access modifier
    class Person {
        private[people]  def sth = 0 //  visible For people pkg
        private[c]       def sth = 0 //  visible For c pkg
        private[this]    def sth = 0 //  visible For This Instance of Person ONLY
        private[MyClass] def sth = 0 //  visible For instances of MyClass

        private[Person]  def sth = 0 //  visible For all instances Of Person
        private          def sth = 0 //  (the same)
    }

Packages

    package a {
      package b {
        package c {
          class Employee  // accessible with  a.b.c.Employee
        }
      }
    }

In scala, the Employee.scala file doesn't have to be in a/b/c directory

In one scala file (Employee.scala), there may be many package structures

    package a {
      package b {
        package c {
          class Employee
        }
      }
    }

    package org {
      package bigjava {
        class Counter {}
      }
    }

Scope Rules

    package a {
      package b {
        package c {

           object Utils {
              def increment(value: Int) = value * 2
           }

           package d {
              class Employee {   //everything from parent packages is accessible
                  def raiseSalary(current:Int) = Utils.increment(current)
              }
           }

        }
      }
    }

So I can use everything under it directly (no need to write scala.collection...)

val subordinates = new collection.mutable.ArrayBuffer[Employee]

If I declare 'package collection {}' anywhere above usage of 'new collection.mutable.ArrayBuffer[Employee]' it will not compile because compiler will first consider my custom 'collection' (not scala.collection) and there's no 'mutable' package in 'collection' declared by me

Workaround:

val subordinates = new scala.collection.mutable.ArrayBuffer[Employee]
// or      
val subordinates = new _root_.scala.collection.mutable.ArrayBuffer[Employee]

Chained packages

 package a.b.c {
   // members of 'a' or 'a.b' are NOT visible here
 }

Top-of-File Notation (instead of nested notation)

It is PREFERRED NOTATION cause in most cases all the code in file belongs to 1 pkg

package a.b.c
package people
class Person {}    // Note that I can also refer to content of a.b.c

is equivalent to

package a.b.c {
    package people {
        class Person {}      // Note that I can also refer to content of a.b.c
            // Until the end of the file
    }
}

Package Objects

A package can contain classes, objects, and traits, but not the definitions of functions or variables

This is a limitation that comes from JVM

However, in scala each package can have one package object (defined in parent pkg, name the same as pkg)

    package world

    package object people {
        val defaultName = "John Q. Public"
    }

    package people {
        class Person {
            var name = defaultName // A constant from the package
        }
    }

Outside 'people' package it is accessible as: world.people.defaultName

Imports can be anywhere

    class Manager {
        import scala.collection.mutable._
        val subordinates = new ArrayBuffer[Employee]
    }

Aliases and Hiding members

    import java.awt.{Color, Font}     // importing two elements  and not the whole package

    import collection.mutable.{HashMap => MyMap} // MyMap is an alias to HashMap
    val m = MyMap(1->11, 2->22)

    import scala.collection.mutable._   // plain HashMap is a scala.collection.mutable.HashMap

    import java.util.{HashMap => _, _}  // importing all (_) except HashMap (HashMap => _)
    import scala.collection.mutable._

Implicit Imports

It's like java.lang in Java

    import java.lang._
    import scala._
    import Predef._  //this could be under scala, but Predef 
                    //... was introduced before Scala had package

java.lang, scala, and Predef packages are always imported

scala.StringBuilder overrides java.lang.StringBuilder instead of conflicting with it.