Scala type keyword: how best to use it across multiple classes

Coming back to Scala after a spell writing Haskell, I've started using the type keyword to make my class definitions a bit more readable, eg:

type RestfulParams = Map[String, String]
def canonicalize(params: RestfulParams): String = { ... }

The trouble I've run into is that these type definitions need to live inside a class or object - they're not "first class citizens" like they are in Haskell. If I try to define a type outside of a class or object, I get a compiler expected class or object definition.

My problem then is how to use these types across multiple classes and objects in a package? What I've done now seems quite ugly:

object RestfulTypes { type RestfulParams = Map[String, String] etc }

And then in another class file:

import utils.{RestfulTypes => RT}
def get(resource: String, params: RT.RestfulParams): String = { ... }

Is there a nicer way of doing this - and incidentally do the Scala gurus think it's a good thing or a bad thing that types can only be defined inside classes/objects?


Solution 1:

Will package objects work for you?

From the article:

Until 2.8, the only things you could put in a package were classes, traits, and standalone objects. These are by far the most common definitions that are placed at the top level of a package, but Scala 2.8 doesn't limit you to just those. Any kind of definition that you can put inside a class, you can also put at the top level of a package. If you have some helper method you'd like to be in scope for an entire package, go ahead and put it right at the top level of the package. To do so, you put the definitions in a package object. Each package is allowed to have one package object. Any definitions placed in a package object are considered members of the package itself.

The package object scala has many types and values already, so I think you can use the same technique for your own types.

Solution 2:

I'm not sure what constitutes niceness in this case, but here are two options:

Using a trait: (Scala's Selfless Trait Pattern)

trait RestfulTypes {
  type Params = Map[String,String]
  //...
}

object MyRestService extends RestService with RestfulTypes { /* ... */ }

Or just import the object's members, effectively using it like a package:

import util.RestfulTypes._