Domas Poliakas
Domas Poliakas

Reputation: 876

Scala implicits and type aliases

Let's say I have the following piece of code:

object Potato extends App {

  type CoolString = String
  type AwesomeString = String

  def potato(string: String)(implicit coolString: CoolString, awesomeString: AwesomeString) = {
    s"$string is a string. Oh, but don't forget - $coolString and also $awesomeString"
  }

  implicit val ice : CoolString = "Really Cold Ice"
  implicit val awe : AwesomeString = "Awe inspiring object"

  potato("Stringerino")

}

This code fails with a problem

[error] ... ambiguous implicit values:
[error]  both value ice in object Potato of type => Potato.CoolString
[error]  and value awe in object Potato of type => Potato.AwesomeString
[error]  match expected type Potato.CoolString
[error]   potato("Stringerino")

Is such use of implicits impossible?

Upvotes: 3

Views: 451

Answers (1)

Yuval Itzchakov
Yuval Itzchakov

Reputation: 149538

Is such use of implicits impossible?

Not only is it impossible, it is dangerous to rely on such a method taking in a type as general as String as an implicit. Think about it, any String instance in scope will be an eligible candidate to get passed into the method!

A type alias is just, well, a type alias, nothing more. To the compiler both CoolString and AwesomeString are merely String.

A better approach is to leverage Tagged Types. For example, this is a tagged type using shapeless:

import shapeless.tag.@@

trait CoolString
trait AwesomeString

type ReallyCoolString = String @@ CoolString
type ReallyAwesomeString = String @@ AwesomeString

And then:

import shapeless.tag

def potato(string: String)(implicit coolString: ReallyCoolString, awesomeString: ReallyAwesomeString) = {
  s"$string is a string. Oh, but don't forget - $coolString and also $awesomeString"
}

def main(args: Array[String]): Unit = {
  implicit val ice = tag[CoolString][String]("Really Cold Ice")
  implicit val awe = tag[AwesomeString][String]("Awe inspiring object")

  println(potato("Stringerino"))
}

Yields:

Stringerino is a string. 
Oh, but don't forget - Really Cold Ice and also Awe inspiring object

Upvotes: 6

Related Questions