1

I was trying to workout the classic example of converting arbitrary values into their Json representation and having compile time errors in case conversion is not defined.

So far, I have,

 trait Json trait ConvertableToJson[A] { def toJson: Json } object Json { case class Str(str: String) extends Json case class Int(int : Int) extends Json case class StrToJson(s: String) extends ConvertableToJson[StrToJson] { override def toJson: Json = Str(s) } } implicit def str2Json(s: String): StrToJson = StrToJson(s) def toJson[A <: ConvertableToJson[A]](a: A) = a.toJson println(toJson("some string")) 

I expected the above code to work like:

toJson("some string") to fail to compile without the implicit def. Because String <: ConvertableToJson[String] is false.

But then to use, the implicit def and find Str2Json.

Str2Json <: ConvertableToJson[Str2Json] should be true.

However, this doesn't happen and compiler complains:

Error: Inferred type arguments [String] do not conform to method toJson's type parameter bounds [A <: scalaz.ConvertToJson.ConvertableToJson[A]] println(toJson("dhruv")) ^ 

It'll be great if someone can help me correct my understanding

1 Answer 1

2

So there are two problems with your code. First of all String does not extend ConvertableToJson[String], which is what your last function call is trying to do.

Second case class StrToJson should extend ConvertableToJson[String] not ConvertableToJson[StrToJson].

Then your code be made to compile by using view-bounds <% (see the working example below). This however is a bad idea because view-bounds are being deprecated as a language feature, you should use type classes instead.

trait Json trait ConvertableToJson[A] { def toJson: Json } object Json { case class Str(str: String) extends Json case class Int(int : Int) extends Json case class StrToJson(s: String) extends ConvertableToJson[String] { override def toJson: Json = Str(s) } } import Json._ implicit def str2Json(s: String): StrToJson = StrToJson(s) def toJson[A <% ConvertableToJson[A]](a: A) = a.toJson println(toJson("some string")) 

Using typeclasses

trait Json trait ConvertableToJson[A] { // NOTE: this now takes a parameter def toJson(a: A): Json } object Json { case class Str(str: String) extends Json case class Int(int : Int) extends Json } import Json._ // NOTE: Because toJson takes a parameter the implicit implementation can now be an object implicit object Str2Json extends ConvertableToJson[String] { override def toJson(a: String): Json = Str(a) } // NOTE: If you want to support the a.toJson syntax this implicit class adds it for all types with an implicit ConvertableToJson implicit class ConvertableToJsonSyntax[A](a: A)(implicit ev: ConvertableToJson[A]) { def toJson: Json = ev.toJson(a) } // NOTE: Now we use context-bounds instead of view-bounds def toJson[A : ConvertableToJson](a: A) = a.toJson // NOTE: we can expand the context-bounds def toJson2[A](a: A)(implicit ev: ConvertableToJson[A]) = a.toJson // NOTE: But since we have the type class instance now, we do not need the extra syntax def toJson3[A](a: A)(implicit ev: ConvertableToJson[A]) = ev.toJson(a) println(toJson("some string")) 
Sign up to request clarification or add additional context in comments.

2 Comments

I understand that String does not extend ConvertableToJson[String] which is why I defined an implicit def of str2Json with signature, String -> ConvertableToJson(StrToString). In my understanding, with this implicit def, scala compiler should be able to convert String into ConvertableToJson[StrToString] which should play well with toJson. Ofcourse it doesn't work and your implementation does, but I still don't see why mine doesn't work. Thanks! :)
On second look it can work if you change the definition of toJson to def toJson[A](a: ConvertableToJson[A]) = a.toJson. Implicit conversions are only triggered when passing a value to into an variable/parameter that takes a different type. They are not triggered for generic parameters types. (You code will continue to work if you removed the generic parameter to ConvertableToJson as it is never used.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.