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

ScalaTypes

Scala Problem Overview


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?

Scala Solutions


Solution 1 - Scala

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 - Scala

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._

Solution 3 - Scala

You can use a package object and put the type declaration in there. When you import that package the type definition will be available.

An example :

//package myType
package object myType {type mine = List[String]}

Notice that the package object has the same name as the package in order to be usable without a object prefix i.e myType.mine If you name it with a different name for example :

//package myType
package object mainType {type mine = List[String]}

it can be accessed with mainType.mine when you import "package"

for more info : http://www.scala-lang.org/docu/files/packageobjects/packageobjects.html

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAlex DeanView Question on Stackoverflow
Solution 1 - ScalaRay ToalView Answer on Stackoverflow
Solution 2 - ScalaKim StebelView Answer on Stackoverflow
Solution 3 - ScalafirephilView Answer on Stackoverflow