Reputation: 3338
I'm trying to implement a bit sophisticated example of typeclasses in Scala: convert value of type T to string implemented as a library a user can extends for any type T. So here's the trait all the typeclasses should implement:
trait Printable[T] {
def asString(value: T): String
}
The function we're going to call to do the job:
object Printer {
def print[T](value: T)(implicit p:Printable[T]): String = p.asString(value)
}
Object with a series of typeclasses for some default types (only int&long here for example):
object SimpleFormats extends Formats
trait Formats {
implicit val intFormat = new Printable[Int] {
override def asString(value: Int) = value.toString
}
implicit val longFormat = new Printable[Long] {
override def asString(value: Long) = value.toString
}
}
Imagine that the user wants to extend our library for some other type, like Float and Double. So he creates another object, subclassing the first one. The idea here is to add new implicit members to the base object so the default collection of typeclasses can be extended for any number of user-supplied types:
object ExtendedFormats extends Formats {
implicit val floatFormat = new Printable[Float] {
override def asString(value: Float) = value.toString
}
implicit val doubleFormat = new Printable[Double] {
override def asString(value: Double) = value.toString
}
}
And finally, the main app using our library. There are two example functions doing operations on different types, so it's not possible to supply single specific implicit Printer[T]
as:
Printer
does not know beforehand which types may be supplied by the user.So the main app looks like this:
object Example {
// compiles OK, uses only default typeclasses
def simpleExample(implicit formats: Formats) = {
import formats._
Printer.print(42) + Printer.print(24L)
}
// compilation failed, cannot find Printable[Float]
// uses user-supplied formats
def extendedExample(implicit formats: Formats) = {
import formats._
Printer.print(42f) + Printer.print(31337.0)
}
def main(args: Array[String]): Unit = {
implicit val formats = ExtendedFormats
println(simpleExample)
println(extendedExample)
}
}
I see that scala compiler tries to import implicits from the Formats
, ignoring the fact that it is ExtendedFormats
actually.
Questions:
Upvotes: 1
Views: 289
Reputation: 2401
If you know in advance that your code needs Printable
for Float
and for Double
then you might declare it directly:
def extendedExample(implicit floatPrintable: Printable[Float], doublePrintable: Printable[Double]) = {
Printer.print(42f) + Printer.print(31337.0)
}
Or create a collection of Format
-like traits:
trait FormatDouble {
implicit val doubleFormat: Printable[Double]
}
and then use it to specify what types do you need:
def extendedExample(implicit formats: Formats with FormatDouble with FormatFloat) = {
import formats._
Printer.print(42f) + Printer.print(31337.0)
}
Upvotes: 2