This page is no longer maintained — Please continue to the home page at www.scala-lang.org

Abstract Types and Type Classes

4 replies
duckworthd
Joined: 2011-09-04,
User offline. Last seen 1 year 7 weeks ago.

I'm currently using [sjson][1] in an effort to serialize a class with
abstract types. For example

class C1 {
type T
val v: T
}

The library dictates that I either use Reflection or Type Classes to
declare how my data is to be written. In order to keep my concerns
separated, I'd like to use the latter. To do so, I must implement
something like the following,

class C1Format extends Format[C1] {
def read(json: JsValue): C1 = { ... }
def write(v: C1): JsValue = { ... }
}

However, this code has a flaw -- I have no way to figure out how to
find Format[C1.T]. If one looks into the source code of sjson itself,
you can find examples of the author handling the case for classes with
parameterized types, such as Seq[T], Map[K,V], etc. For example,

implicit def listFormat[T](implicit fmt : Format[T]) :
Format[List[T]] = new Format[List[T]] {
def writes(ts: List[T]) = JsArray(ts.map(t => tojson(t)(fmt)))
def reads(json: JsValue) = json match {
case JsArray(ts) => ts.map(t => fromjson(t)(fmt))
case _ => throw new RuntimeException("List expected")
}
}

With Parameterized Types, it's clear how to give the unknown type T a
name, and thus retrieve Format[T]. How can I do the same for an
Abstract type?

[1]: https://github.com/debasishg/sjson

David Hall 4
Joined: 2009-08-21,
User offline. Last seen 42 years 45 weeks ago.
Re: Abstract Types and Type Classes

This may or may not work for your needs, but it's the basic idea:

scala> trait Foo { type T ; def foo : T }
defined trait Foo

scala> trait Format[F] { def make: F}
defined trait Format

scala> implicit def formatF[TT](implicit format: Format[TT]) = {
| new Format[Foo { type T = TT; }] { def make = new Foo { type T
= TT; def foo = format.make } }
| }
formatF: [TT](implicit format: Format[TT])java.lang.Object with
Format[Foo{type T = TT}]

scala> implicit val x = new Format[Int] { def make = 3 }
x: java.lang.Object with Format[Int] = $anon$1@4f4f4c7a

scala> formatF[Int].make
res0: Foo{type T = Int} = $anon$1$$anon$2@2a6788c4

scala> res0.foo
res1: res0.T = 3

On Fri, Oct 14, 2011 at 11:46 PM, Daniel Duckworth wrote:
> I'm currently using [sjson][1] in an effort to serialize a class with
> abstract types.  For example
>
>    class C1 {
>        type T
>        val v: T
>    }
>
> The library dictates that I either use Reflection or Type Classes to
> declare how my data is to be written.  In order to keep my concerns
> separated, I'd like to use the latter.  To do so, I must implement
> something like the following,
>
>    class C1Format extends Format[C1] {
>        def read(json: JsValue): C1 = { ... }
>        def write(v: C1): JsValue = { ... }
>    }
>
> However, this code has a flaw -- I have no way to figure out how to
> find Format[C1.T].  If one looks into the source code of sjson itself,
> you can find examples of the author handling the case for classes with
> parameterized types, such as Seq[T], Map[K,V], etc.  For example,
>
>    implicit def listFormat[T](implicit fmt : Format[T]) :
> Format[List[T]] = new Format[List[T]] {
>      def writes(ts: List[T]) = JsArray(ts.map(t => tojson(t)(fmt)))
>      def reads(json: JsValue) = json match {
>        case JsArray(ts) => ts.map(t => fromjson(t)(fmt))
>        case _ => throw new RuntimeException("List expected")
>      }
>    }
>
> With Parameterized Types, it's clear how to give the unknown type T a
> name, and thus retrieve Format[T].  How can I do the same for an
> Abstract type?
>
>  [1]: https://github.com/debasishg/sjson

debasish
Joined: 2011-06-19,
User offline. Last seen 42 years 45 weeks ago.
Re: Abstract Types and Type Classes
Hi Daniel -
When u define a class like 
class C1 {  type T   val v: T}
it's an abstract class. And the current implementation of typeclass based serialization assumes that u return a concrete instance of the class from the def reads .. method. Hence this is currently not supported. However, you can do the typeclass thing with the concrete implementation of C1. Here's a sample ..
abstract class C1 {  type T   val v: T}
case class CC1(v: String) extends C1 {  type T = String }
object CC1 extends DefaultProtocol {   import dispatch.json._  import JsonSerialization._
  implicit object CC1Format extends Format[CC1] {     def reads(json: JsValue): CC1 = json match {      case JsObject(m) => CC1(fromjson[String](m(JsString("v"))))        case _ => throw new RuntimeException("JsObject expected")    }     def writes(c1: CC1): JsValue = JsObject(List((tojson("v").asInstanceOf[JsString], tojson(c1.v))))  } }
describe("Serialization of items with abstract types") {   it("should serialize") {    val c = CC1("debasish ghosh")     fromjson[CC1](tojson(c)) should equal(c)  } }

Hope this helps ..

On Sat, Oct 15, 2011 at 12:16 PM, Daniel Duckworth <duckworthd [at] gmail [dot] com> wrote:
I'm currently using [sjson][1] in an effort to serialize a class with
abstract types.  For example

   class C1 {
       type T
       val v: T
   }

The library dictates that I either use Reflection or Type Classes to
declare how my data is to be written.  In order to keep my concerns
separated, I'd like to use the latter.  To do so, I must implement
something like the following,

   class C1Format extends Format[C1] {
       def read(json: JsValue): C1 = { ... }
       def write(v: C1): JsValue = { ... }
   }

However, this code has a flaw -- I have no way to figure out how to
find Format[C1.T].  If one looks into the source code of sjson itself,
you can find examples of the author handling the case for classes with
parameterized types, such as Seq[T], Map[K,V], etc.  For example,

   implicit def listFormat[T](implicit fmt : Format[T]) :
Format[List[T]] = new Format[List[T]] {
     def writes(ts: List[T]) = JsArray(ts.map(t => tojson(t)(fmt)))
     def reads(json: JsValue) = json match {
       case JsArray(ts) => ts.map(t => fromjson(t)(fmt))
       case _ => throw new RuntimeException("List expected")
     }
   }

With Parameterized Types, it's clear how to give the unknown type T a
name, and thus retrieve Format[T].  How can I do the same for an
Abstract type?

 [1]: https://github.com/debasishg/sjson



--
Debasish Ghosh
http://manning.com/ghosh

Twttr: @debasishg
Blog: http://debasishg.blogspot.com
Code: http://github.com/debasishg
duckworthd
Joined: 2011-09-04,
User offline. Last seen 1 year 7 weeks ago.
Re: Abstract Types and Type Classes
Hi Debasish, David,
Actually, David's solution worked just fine.  I've successfully got Scalala's DenseVector[T] and Graph for Scala's LDiEdge[T]{type L1} to serialize/deserialize without a hitch.  I think my example was a bad, thus the confusion.
Rather than trying to serialize a fully abstract class, I hoped to serialize something implemented completely up to its types.  You've already done this with the core Scala collections -- I just sought to do it with objects with abstract types as well.  In my example a concrete subclass would be needed, and were there 2 subclasses CC1 and CC2 of C1, then creating an implicit Format[C1] would be a terrible idea -- while I could view CC1 and CC2 both as C1, my Format[C1] would have to choose to instantiate one or the other.
Luckily, that's not quite the case here.  Thank you both very much!  I've learned that much more Scala-fu today.
Daniel Duckworth


On Sat, Oct 15, 2011 at 2:50 AM, Debasish Ghosh <ghosh [dot] debasish [at] gmail [dot] com> wrote:
Hi Daniel -
When u define a class like 
class C1 {  type T   val v: T}
it's an abstract class. And the current implementation of typeclass based serialization assumes that u return a concrete instance of the class from the def reads .. method. Hence this is currently not supported. However, you can do the typeclass thing with the concrete implementation of C1. Here's a sample ..
abstract class C1 {  type T   val v: T}
case class CC1(v: String) extends C1 {  type T = String }
object CC1 extends DefaultProtocol {   import dispatch.json._  import JsonSerialization._
  implicit object CC1Format extends Format[CC1] {     def reads(json: JsValue): CC1 = json match {      case JsObject(m) => CC1(fromjson[String](m(JsString("v"))))        case _ => throw new RuntimeException("JsObject expected")    }     def writes(c1: CC1): JsValue = JsObject(List((tojson("v").asInstanceOf[JsString], tojson(c1.v))))  } }
describe("Serialization of items with abstract types") {   it("should serialize") {    val c = CC1("debasish ghosh")     fromjson[CC1](tojson(c)) should equal(c)  } }

Hope this helps ..

On Sat, Oct 15, 2011 at 12:16 PM, Daniel Duckworth <duckworthd [at] gmail [dot] com> wrote:
I'm currently using [sjson][1] in an effort to serialize a class with
abstract types.  For example

   class C1 {
       type T
       val v: T
   }

The library dictates that I either use Reflection or Type Classes to
declare how my data is to be written.  In order to keep my concerns
separated, I'd like to use the latter.  To do so, I must implement
something like the following,

   class C1Format extends Format[C1] {
       def read(json: JsValue): C1 = { ... }
       def write(v: C1): JsValue = { ... }
   }

However, this code has a flaw -- I have no way to figure out how to
find Format[C1.T].  If one looks into the source code of sjson itself,
you can find examples of the author handling the case for classes with
parameterized types, such as Seq[T], Map[K,V], etc.  For example,

   implicit def listFormat[T](implicit fmt : Format[T]) :
Format[List[T]] = new Format[List[T]] {
     def writes(ts: List[T]) = JsArray(ts.map(t => tojson(t)(fmt)))
     def reads(json: JsValue) = json match {
       case JsArray(ts) => ts.map(t => fromjson(t)(fmt))
       case _ => throw new RuntimeException("List expected")
     }
   }

With Parameterized Types, it's clear how to give the unknown type T a
name, and thus retrieve Format[T].  How can I do the same for an
Abstract type?

 [1]: https://github.com/debasishg/sjson



--
Debasish Ghosh
http://manning.com/ghosh

Twttr: @debasishg
Blog: http://debasishg.blogspot.com
Code: http://github.com/debasishg

debasish
Joined: 2011-06-19,
User offline. Last seen 42 years 45 weeks ago.
Re: Abstract Types and Type Classes
Cool .. Thanks for using sjson ..

On Sat, Oct 15, 2011 at 3:54 PM, Daniel Duckworth <duckworthd [at] gmail [dot] com> wrote:
Hi Debasish, David,
Actually, David's solution worked just fine.  I've successfully got Scalala's DenseVector[T] and Graph for Scala's LDiEdge[T]{type L1} to serialize/deserialize without a hitch.  I think my example was a bad, thus the confusion.
Rather than trying to serialize a fully abstract class, I hoped to serialize something implemented completely up to its types.  You've already done this with the core Scala collections -- I just sought to do it with objects with abstract types as well.  In my example a concrete subclass would be needed, and were there 2 subclasses CC1 and CC2 of C1, then creating an implicit Format[C1] would be a terrible idea -- while I could view CC1 and CC2 both as C1, my Format[C1] would have to choose to instantiate one or the other.
Luckily, that's not quite the case here.  Thank you both very much!  I've learned that much more Scala-fu today.
Daniel Duckworth


On Sat, Oct 15, 2011 at 2:50 AM, Debasish Ghosh <ghosh [dot] debasish [at] gmail [dot] com> wrote:
Hi Daniel -
When u define a class like 
class C1 {  type T   val v: T}
it's an abstract class. And the current implementation of typeclass based serialization assumes that u return a concrete instance of the class from the def reads .. method. Hence this is currently not supported. However, you can do the typeclass thing with the concrete implementation of C1. Here's a sample ..
abstract class C1 {  type T   val v: T}
case class CC1(v: String) extends C1 {  type T = String }
object CC1 extends DefaultProtocol {   import dispatch.json._  import JsonSerialization._
  implicit object CC1Format extends Format[CC1] {     def reads(json: JsValue): CC1 = json match {      case JsObject(m) => CC1(fromjson[String](m(JsString("v"))))        case _ => throw new RuntimeException("JsObject expected")    }     def writes(c1: CC1): JsValue = JsObject(List((tojson("v").asInstanceOf[JsString], tojson(c1.v))))  } }
describe("Serialization of items with abstract types") {   it("should serialize") {    val c = CC1("debasish ghosh")     fromjson[CC1](tojson(c)) should equal(c)  } }

Hope this helps ..

On Sat, Oct 15, 2011 at 12:16 PM, Daniel Duckworth <duckworthd [at] gmail [dot] com> wrote:
I'm currently using [sjson][1] in an effort to serialize a class with
abstract types.  For example

   class C1 {
       type T
       val v: T
   }

The library dictates that I either use Reflection or Type Classes to
declare how my data is to be written.  In order to keep my concerns
separated, I'd like to use the latter.  To do so, I must implement
something like the following,

   class C1Format extends Format[C1] {
       def read(json: JsValue): C1 = { ... }
       def write(v: C1): JsValue = { ... }
   }

However, this code has a flaw -- I have no way to figure out how to
find Format[C1.T].  If one looks into the source code of sjson itself,
you can find examples of the author handling the case for classes with
parameterized types, such as Seq[T], Map[K,V], etc.  For example,

   implicit def listFormat[T](implicit fmt : Format[T]) :
Format[List[T]] = new Format[List[T]] {
     def writes(ts: List[T]) = JsArray(ts.map(t => tojson(t)(fmt)))
     def reads(json: JsValue) = json match {
       case JsArray(ts) => ts.map(t => fromjson(t)(fmt))
       case _ => throw new RuntimeException("List expected")
     }
   }

With Parameterized Types, it's clear how to give the unknown type T a
name, and thus retrieve Format[T].  How can I do the same for an
Abstract type?

 [1]: https://github.com/debasishg/sjson



--
Debasish Ghosh
http://manning.com/ghosh

Twttr: @debasishg
Blog: http://debasishg.blogspot.com
Code: http://github.com/debasishg




--
Debasish Ghosh
http://manning.com/ghosh

Twttr: @debasishg
Blog: http://debasishg.blogspot.com
Code: http://github.com/debasishg

Copyright © 2012 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland