I am attempting to use implicits to try and override a serialize method that I have inside case classes for an ADT, however I am unable to get my head around how it should be done
// START OF API//
/**
* Serialize methods defined here
*
*/
object Serializer {
def string(block: (String => String)) = block
def int(block:(Int => String)) = block
def double(block:(Double => String)) = block
}
/**
* These are the DEFAULT serializers
*/
object Implicits {
implicit val string = Serializer.string (s => s)
implicit val int = Serializer.int (i => i.toString)
implicit val double = Serializer.double (d => String.valueOf(d))
}
/**
*
* Our simple ADT defined here
*/
import Implicits._
abstract class Vehicle {
def serialize:String
}
case class Car(s:String) extends Vehicle {
def serialize: String = string(s)
}
case class Truck(i:Int) extends Vehicle {
def serialize: String = int(i)
}
case class RocketShip(d:Double) extends Vehicle {
def serialize: String = double(d)
}
// END OF API
// START OF USER CODE
object UserImplicit {
implicit val string = Serializer.string(s => s.capitalize)
}
object Main extends App{
val v = Car("some car")
println(v.serialize)
import test.UserImplicit._
// This SHOULD print a capatilized version i.e. SOME CAR
println(v.serialize)
}
// END OF USER CODE
Basically I want to monkey patch the default serializer methods (the ones contained inside object Implicits
) so that users of the API can implement their own serializers
I have tried many combinations (such as having the implicits inside a trait
instead of a object
) however I havn't actually managed to get it working
I actually managed to figure it out using the pimp my library pattern, here is an example of the working code
object Implicits {
def defaults(v:Vehicle):String = {
v match {
case Car(c) => "This is car " + c
case Truck(t) => "This is a truct " + t
case RocketShip(r) => "This is a rocketship " + r
}
}
class VehicleSerializer(v:Vehicle) {
def serialize:String = defaults(v)
}
implicit def vSerialize(v:Vehicle) = new VehicleSerializer(v)
}
/**
* Our simple ADT defined here
*/
abstract class Vehicle {}
case class Car(s: String) extends Vehicle {}
case class Truck(i: Int) extends Vehicle {}
case class RocketShip(d: Double) extends Vehicle {}
// END OF API
// START OF USER CODE
class UserImplicit(v:Vehicle) {
def serialize:String = {
v match {
case Car(c) => "This is a MASSIVE car " + c
case _v => Implicits.defaults(_v)
}
}
}
object Test extends App {
val c = Car("rawr")
// This is the default serializer
{
import Implicits._
println(c.serialize)
}
// This is our overwritten serializer
{
implicit def vSerialize(v:Vehicle) = new UserImplicit(v)
println(c.serialize)
}
}
// END OF USER CODE
which prints
This is car rawr
This is a MASSIVE car rawr
As intended