Within Scala, is it possible to alias a type but disallow cross-use of aliased/non-aliased types like Haskell?

Another option would be to use value classes. These create a wrapper around an underlying type which is converted into direct access to the raw type at compile time, with methods on the class being converted into static calls on an associated companion object. For example:

class CM(val quant : Double) extends AnyVal {
  def +(b : CM) = new CM(quant + b.quant)
  def *(b : Int) = new CM(quant * b)
}

Yeah you using something known as Unboxed Tagged Types in scala.

This is how Tagged is defined:

type Tagged[U] = { type Tag = U }
type @@[T, U] = T with Tagged[U]

This allows you to do something like this

sealed trait Feet

def Feet[A](a: A): A @@ Feet = Tag[A, Feet](a)
Feet: [A](a: A)scalaz.@@[A,Feet]

scala> val mass = Feet(20.0)
mass: scalaz.@@[Double,Feet] = 20.0

scala> 2 * mass
res2: Double = 40.0

to also add CM

sealed trait CM

def CM[A](a: A): A @@ CM = Tag[A, CM](a)
CM: [A](a: A)scalaz.@@[A,CM]

scala> val mass = CM(20.0)
mass: scalaz.@@[Double,CM] = 20.0

If you want to restrict multiplication to only Feet then you could write a typeclass type multiplication function

trait Multiply[T] { self =>
   def multiply(a: T, b: T): T
}
implicit val footInstance = new Multiply[Feet] {
   def multiply(a: Feet, b: Feet): Feet = Feet(a * b)
}
implicit val cmInstance = new Multiply[CM] {
  def multiply(a: CM, b: CM): CM = CM(a * b)
}

def multiply[T: Multiply](a: T, b: T): T = {
  val multi = implicitly[Multiply[T]]
  multi.multiply(a,b)
} 

you can then do

multiply(Feet(5), Feet(10)) // would return Feet(50)

this is the best Scala can do

To learn more about the boxed type check out http://eed3si9n.com/learning-scalaz-day3


You could use NewType from the scala-newtype library!

Shameless plug: I am the author of scala-newtype

https://github.com/estatico/scala-newtype

This combines the ideas from Scalaz and Shapeless as well as introduces ideas straight from Haskell (like GeneralizedNewTypeDeriving).

Here's what the your code may look like using newtype. We'll give both Feet and Cm their own distinct types and have them derive the Numeric type class based on the one for Double (which deriving does automatically).

We can then use the extension methods provided by Numeric.Implicits -

object Example {

  type Feet = Feet.Type
  object Feet extends NewType.Default[Double] {
    implicit val num: Numeric[Type] = deriving
  }

  type Cm = Cm.Type
  object Cm extends NewType.Default[Double] {
    implicit val num: Numeric[Type] = deriving
  }

  val widthInFeet = Feet(1.0)
  val widthInCm = Cm(30.48)

  import Numeric.Implicits._

  // Does not compile:
  // val nonsense = widthInFeet + widthInCm

  // Compiles!
  val doubleWidthInFeet: Feet = widthInFeet + widthInFeet
}

However, you use * in the example, and we wouldn't want Feet * Feet = Feet as it should really be Feet * Feet = Feet², so let's add a FeetSq type to represent that and define our own operations to be more type safe than Numeric -

object Example {

  type Feet = Feet.Type
  object Feet extends NewType.Default[Double] {
    implicit final class Ops(val self: Feet) extends AnyVal {
      def +(other: Feet) = Feet(self.repr + other.repr)
      def -(other: Feet) = Feet(self.repr - other.repr)
      def *(other: Feet) = FeetSq(self.repr * other.repr)
    }
  }

  type FeetSq = FeetSq.Type
  object FeetSq extends NewType.Default[Double]

  type Cm = Cm.Type
  object Cm extends NewType.Default[Double]

  val widthInFeet = Feet(1.0)
  val widthInCm = Cm(30.48)

  // Does not compile:
  // val nonsense = widthInFeet * widthInCm

  // Compiles!
  val squareFeet: FeetSq = widthInFeet * widthInFeet
}

Here we're using an implicit final class Ops to define methods on our newtype. This class is eliminated at compile time, so at runtime we just end up calling extension methods from the Ops object.