packages

First thing to note about packages in Scala is that you cannot simply chuck a bunch of functions and variables inside a package and expect everything to work as expected.

All the behavior you need has to be wrapped in class or object construct. Bare functions are not allowed.

Use Case

As a developer I want to be able to share a useful method across different files.

Decide if you want the functionality to be static or instance based. In the case below I will go with static, no need for a specific instance.

Directory organization is up to you, Scala does not enforce a specific directory structure for packages, but being organized has its benefits.

A directory structure like this this would work:

└── /src
  └── /useful
      └── utils.scala

My intent is to create a directory /userful with a file called utils.scala that will house all the methods I want to share. Yes, this can turn into a junk drawer but this is simply an example to help get things wired up.

Now inside the Scala file utils.scala you will want to do something like:

package useful {
  object Utils  {
    def say_hello (s: Any) = {
      println("Hello " + s)
    }
  }
}

Now this by itself is not really useful. To use it in some other file:

└── /src
  └── /things
      └── speaker.scala

You need to import it. So in the top of speaker.scala do this:

import useful._

The ._ notation allows you to pull in all the methods in the useful package.

Now you can use the use the packaged method like:

import useful._
object Speaker extends App {
 Utils.say_hello(Console.YELLOW + Console.WHITE_B + "Hello")
}

Visibility

Passing Example

A method can be declared private then it can only be run inside the package it was tagged with and no where else. Here is an example:

// Big Package
package kitchen {
  package drawer {
    package sharp_things {
      class Knife {
        //Public Scope
        def handle = "Hold Me"
        //Only works in sharp things
        private[sharp_things] def cut = "Cut things!"  
        //Only works in ktichen
        private[kitchen] def chop = "Chop Chop!"  
      }
    }
  }
}
//Small Specific Package using the big Package
import kitchen.drawer.sharp_things._
package kitchen {
  class SharpObjects {
    def chop_it() = {
      val knife = new Knife
      knife.chop
    }
  }
}

Here we are calling chop on knife from inside of the kitchen package. This would not work from inside of any other package but kitchen because we have used private[kitchen] in front of the def chop method definition .

Failing Example

Lets say you call a method from the wrong package (package it has not been tagged with). It will fail to compile:

import kitchen.SharpObjects

package kitchen {
  package drawer {
    package sharp_things {
      class Knife {
        //Only works in sharp things
        private[sharp_things] def cut = "Cut thing!"  
        def handle = "HOLD ME"
        //Only works in kitchen
        private[kitchen] def chop = "Chop Chop!"  
      }
    }
  }
}
import kitchen.drawer.sharp_things._
package kitchen {
  class SharpObjects {
    def cut_it() = {
      val r = new Knife
      r.cut //This is tagged with sharp_things NOT kitchen
    }
  }
}

Remapping the names

Package members can be selectively renamed to make dealing with the code a bit easier. The snip below illustrates how a poorly named knife can actually be used as axe:

package kitchen {
  package drawer {
    //WTF??
    class Knife {
      def chop = "Big Chop"
    }
    package sharp_things {
      //Damn not again!?
      class Knife {
        //stuff  
      }
    }
  }
}

import kitchen._
object driver extends App {
  // Apply rename goodness!
  import kitchen.drawer.{Knife => Axe}
  val axe = new Axe
  println(axe.chop)
}

Hiding members

Packages can have members totally hidden if need be.

The following completely hides the member from being used:

//Knife is no longer importable from kitchen.drawer
import kitchen.drawer.{Knife => _ }  
// Has Knife inside
import kitchen.drawer.SharpObjects._

Now in the code the only Knife that can be used is the one in import kitchen.drawer.SharpObjects._