Cory Klein
Cory Klein

Reputation: 55690

Renaming the Option, Some, and None sealed types to a domain-specific language?

I'd like to declare some types that are Option, Some, and None but are referred to by different names that are more apropos to my domain in order to improve code readability. Because although the functionality of Option does map 1:1 to my problem domain, it's not exactly obvious at first glance so calling this type "Option" would be confusing.

My first thought was to use type aliases:

type Foo[T] = Option[T]
type Bar[T] = Some[T]
type Bash = None.type

However, I can't use this new "language" when pattern matching:

def example(f: Foo[Int]) = f match {
  case Bar(_) => "got bar"
  case Bash => "got bash"
}
/*
On line 2: error: not found: value Bar
         case Bash => "got bash"
              ^
On line 3: error: not found: value Bash
       Identifiers that begin with uppercase are not pattern variables but match the value in scope.
*/

Next I thought to simply subclass, but Option is sealed – for good reason – so that's out of the picture:

trait Foo[T] extends Option[T]
// error: illegal inheritance from sealed class Option

Last of all I thought I was clever in trying to rename on import:

// BEGIN Foo.scala
import scala.{Option => Foo}
import scala.{Some => Bar}
import scala.{None => Bash}

// This works!
def example(f: Foo[Int]) = f match {
  case Bar(_) => "got bar"
  case Bash => "got bash"
}

... but there is no way to export the newly declared names for use outside of the current file 😔:

// BEGIN OtherFileThatUsesFoo.scala

// Doesn't compile because Option must be called either "Option" or "Foo" and not both
case class Person(child: Option[Person], foo: Foo[Int]) 

Is there another option I'm missing, besides simply implementing Option with a different name?

Upvotes: 0

Views: 93

Answers (1)

Cory Klein
Cory Klein

Reputation: 55690

And @Luis Miguel Mejía Suárez has it in the comments!

type Foo[T] = Option[T]
val Foo = Option
type Bar[T] = Some[T]
val Bar = Some
type Bash = None.type
val Bash = None

// Compiles and runs correctly!
def example(f: Foo[Int]) = f match {
  case Bar(_) => "got bar"
  case Bash => "got bash"
}

I needed to "alias" the companion objects as well, a la val Foo = Option.

Upvotes: 1

Related Questions