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

Type parametrizations and erasure

5 replies
mailleux
Joined: 2008-08-23,
User offline. Last seen 4 years 7 weeks ago.
I have been playing with parametrises type, and every once in a while I run into problems. I may be doing things the wrong way or not supported.
Let me tell the story and then what happens.

I have an actor that has several containers in it. I'd like to send a query function to it, have it map the function on the collections (which depends on the parameter type), and the actor reply a sequence. In essence the messages should be like this:

case class Query[T,S](func:T=>S)
case class Response[S](resp:Seq[S])

And I'd do:

func:Function[A,B]
func2:Fuction[C,D]

a) actor !? Query(func) 

Desired behavior of actor: 

   reply(Response(coll_a.map(func).toSeq))    // where coll_a:List[A]

b) actor !? Query(func2) 

Desired behavior of actor: 

   reply(Response(coll_b.map(func).toSeq))    // where coll_b:List[B]

So actor has to choose coll_a or coll_b using either depdintin on the T of Query[T,S]. I can't seem to find a way to reason on the T information. And erasures will destroy other types of matching like

if(func.isInstanceOf[Function[A,_]])

As an alternative, I have tested this code, I use an enumeration to specify the target of the query. This way I can match the query to the correct collection:

case class Query[T,S](target:Query.target.Value, query:T=>S)
case class Response[S](resp:Seq[S])


However to make my life easiser  I created a function that runs the query and gets the response:


def queryObjs[R](actor:Actor,func:Obj=>R):Seq[R] forSome {type R} = {
  var resp=actor !? Query(Query.target.MapObj,func)
  resp match {
    case Response(s:Seq[R]) => s.asInstanceOf[Seq[R]]
    case _ => throw new Exception("Bad reply from query")
  }
}

The code above works, but I need to create one function for each target. I'd like to create  e generic function query[Q,R], but that fails on run-time.

Is there a more elegante way to get the generic Query/Response model?

Thomas

Jorge Ortiz
Joined: 2008-12-16,
User offline. Last seen 29 weeks 3 days ago.
Re: Type parametrizations and erasure
Read my blog post on Manifests: http://scala-blogs.org/2008/10/manifests-reified-types.html

scala> case class Query[T, S](func: T => S)(implicit val t: scala.reflect.Manifest[T], val s: scala.reflect.Manifest[S])
defined class Query

scala> val q = Query((x: Int) => (x + 1).toString)
q: Query[Int,java.lang.String] = Query(<function>)

scala> q.s.toString
res2: java.lang.String = java.lang.String

scala> q.t.toString
res3: java.lang.String = int

--j

On Mon, Dec 22, 2008 at 10:08 AM, Thomas Sant Ana <mailleux [at] gmail [dot] com> wrote:
I have been playing with parametrises type, and every once in a while I run into problems. I may be doing things the wrong way or not supported.
Let me tell the story and then what happens.

I have an actor that has several containers in it. I'd like to send a query function to it, have it map the function on the collections (which depends on the parameter type), and the actor reply a sequence. In essence the messages should be like this:

case class Query[T,S](func:T=>S)
case class Response[S](resp:Seq[S])

And I'd do:

func:Function[A,B]
func2:Fuction[C,D]

a) actor !? Query(func) 

Desired behavior of actor: 

   reply(Response(coll_a.map(func).toSeq))    // where coll_a:List[A]

b) actor !? Query(func2) 

Desired behavior of actor: 

   reply(Response(coll_b.map(func).toSeq))    // where coll_b:List[B]

So actor has to choose coll_a or coll_b using either depdintin on the T of Query[T,S]. I can't seem to find a way to reason on the T information. And erasures will destroy other types of matching like

if(func.isInstanceOf[Function[A,_]])

As an alternative, I have tested this code, I use an enumeration to specify the target of the query. This way I can match the query to the correct collection:

case class Query[T,S](target:Query.target.Value, query:T=>S)
case class Response[S](resp:Seq[S])


However to make my life easiser  I created a function that runs the query and gets the response:


def queryObjs[R](actor:Actor,func:Obj=>R):Seq[R] forSome {type R} = {
  var resp=actor !? Query(Query.target.MapObj,func)
  resp match {
    case Response(s:Seq[R]) => s.asInstanceOf[Seq[R]]
    case _ => throw new Exception("Bad reply from query")
  }
}

The code above works, but I need to create one function for each target. I'd like to create  e generic function query[Q,R], but that fails on run-time.

Is there a more elegante way to get the generic Query/Response model?

Thomas


mailleux
Joined: 2008-08-23,
User offline. Last seen 4 years 7 weeks ago.
Re: Type parametrizations and erasure
The Manifest did half the work. I defined them this way:

case class Query3[Q,R](query:Q=>R,tq:scala.reflect.Manifest[Q],tr:scala.reflect.Manifest[R])
case class Response[S](resp:Seq[S])(implicit val ts:scala.reflect.Manifest[Seq[S]])


I now can handle the correct type for the function in the actor. This code really makes it easier:

    case Query3(func,tq,tr) =>
      println("QUery of "+tq+" Reply "+tr)
      tq.toString match {
        case "java.lang.String" => reply(Response(map.map(x=>func(x._1)).toSeq))
        case "int" => reply(Response(map.map(x=>func(x._2)).toSeq))
      }

However the Response is always a Seq[java.lang.Object].
  def query[Q,R](actor:Actor,func:Q=>R)(implicit tq:scala.reflect.Manifest[Q],tr:scala.reflect.Manifest[R]):Seq[R] forSome{ type Q; type R}= {
    println("query type of source "+tq.toString)
    var resp=actor !? Query3(func,tq,tr)
    resp match {
      case Response(s:Seq[R]) => //if(scala.reflect.Manifest[R])=>
        println("Type of responce: "+resp.asInstanceOf[Response[R]].ts.toString)
        s.asInstanceOf[Seq[R]]
      case s => throw new Exception("Bad reply from query"+s)
    }
}

    resp=query(ma,((x:Int)=>Math.sqrt(x.toFloat)))
    println(resp)

Yields:

query type of source int
Type of responce: scala.Seq[java.lang.Object]
ArrayBuffer(4.47213595499958, 3.1622776601683795)

I believe the "case" squashes the type information, is there a way to make replies typed?

Thomas

On Mon, Dec 22, 2008 at 3:45 PM, Jorge Ortiz <jorge [dot] ortiz [at] gmail [dot] com> wrote:
Read my blog post on Manifests: http://scala-blogs.org/2008/10/manifests-reified-types.html

scala> case class Query[T, S](func: T => S)(implicit val t: scala.reflect.Manifest[T], val s: scala.reflect.Manifest[S])
defined class Query

scala> val q = Query((x: Int) => (x + 1).toString)
q: Query[Int,java.lang.String] = Query(<function>)

scala> q.s.toString
res2: java.lang.String = java.lang.String

scala> q.t.toString
res3: java.lang.String = int

--j

On Mon, Dec 22, 2008 at 10:08 AM, Thomas Sant Ana <mailleux [at] gmail [dot] com> wrote:
I have been playing with parametrises type, and every once in a while I run into problems. I may be doing things the wrong way or not supported.
Let me tell the story and then what happens.

I have an actor that has several containers in it. I'd like to send a query function to it, have it map the function on the collections (which depends on the parameter type), and the actor reply a sequence. In essence the messages should be like this:

case class Query[T,S](func:T=>S)
case class Response[S](resp:Seq[S])

And I'd do:

func:Function[A,B]
func2:Fuction[C,D]

a) actor !? Query(func) 

Desired behavior of actor: 

   reply(Response(coll_a.map(func).toSeq))    // where coll_a:List[A]

b) actor !? Query(func2) 

Desired behavior of actor: 

   reply(Response(coll_b.map(func).toSeq))    // where coll_b:List[B]

So actor has to choose coll_a or coll_b using either depdintin on the T of Query[T,S]. I can't seem to find a way to reason on the T information. And erasures will destroy other types of matching like

if(func.isInstanceOf[Function[A,_]])

As an alternative, I have tested this code, I use an enumeration to specify the target of the query. This way I can match the query to the correct collection:

case class Query[T,S](target:Query.target.Value, query:T=>S)
case class Response[S](resp:Seq[S])


However to make my life easiser  I created a function that runs the query and gets the response:


def queryObjs[R](actor:Actor,func:Obj=>R):Seq[R] forSome {type R} = {
  var resp=actor !? Query(Query.target.MapObj,func)
  resp match {
    case Response(s:Seq[R]) => s.asInstanceOf[Seq[R]]
    case _ => throw new Exception("Bad reply from query")
  }
}

The code above works, but I need to create one function for each target. I'd like to create  e generic function query[Q,R], but that fails on run-time.

Is there a more elegante way to get the generic Query/Response model?

Thomas



Jorge Ortiz
Joined: 2008-12-16,
User offline. Last seen 29 weeks 3 days ago.
Re: Type parametrizations and erasure
You have to make sure that the place where you do reply(Response(...)) has enough type information about the Seq inside the Response.

But try something like:

  import scala.reflect.Manifest

  case class Query[Q, R](query: Q => R)(implicit val tq: Manifest[Q], val tr: Manifest[R])
  case class Response[R, S <: Seq[R]](resp: S)(implicit val tr: Manifest[R], val ts: Manifest[S])

  case query @ Query(fn) =>
    println("Query of "+query.tq+" Reply "+query.tr)
    query.tq.toString match {
      case "java.lang.String" => reply(Response(map.map(x => func(x._1)).toSeq))
      case "int" => reply(Response(map.map(x => func(x._2)).toSeq))
    }

  val q: Query[Q, R] = Query(func)
  (actor !? q) match {
    case r @ Response(s) =>
      println("Type of response: " + r.ts.toString)
      r.tr.toString match {
        case q.tr.toString => s.asInstanceOf[Seq[R]]
        case _ => throw new Exception
      }
  }

--j

On Mon, Dec 22, 2008 at 6:14 PM, Thomas Sant Ana <mailleux [at] gmail [dot] com> wrote:
The Manifest did half the work. I defined them this way:

case class Query3[Q,R](query:Q=>R,tq:scala.reflect.Manifest[Q],tr:scala.reflect.Manifest[R])
case class Response[S](resp:Seq[S])(implicit val ts:scala.reflect.Manifest[Seq[S]])


I now can handle the correct type for the function in the actor. This code really makes it easier:

    case Query3(func,tq,tr) =>
      println("QUery of "+tq+" Reply "+tr)
      tq.toString match {
        case "java.lang.String" => reply(Response(map.map(x=>func(x._1)).toSeq))
        case "int" => reply(Response(map.map(x=>func(x._2)).toSeq))
      }

However the Response is always a Seq[java.lang.Object].
  def query[Q,R](actor:Actor,func:Q=>R)(implicit tq:scala.reflect.Manifest[Q],tr:scala.reflect.Manifest[R]):Seq[R] forSome{ type Q; type R}= {
    println("query type of source "+tq.toString)
    var resp=actor !? Query3(func,tq,tr)
    resp match {
      case Response(s:Seq[R]) => //if(scala.reflect.Manifest[R])=>
        println("Type of responce: "+resp.asInstanceOf[Response[R]].ts.toString)
        s.asInstanceOf[Seq[R]]
      case s => throw new Exception("Bad reply from query"+s)
    }
}

    resp=query(ma,((x:Int)=>Math.sqrt(x.toFloat)))
    println(resp)

Yields:

query type of source int
Type of responce: scala.Seq[java.lang.Object]
ArrayBuffer(4.47213595499958, 3.1622776601683795)

I believe the "case" squashes the type information, is there a way to make replies typed?

Thomas

On Mon, Dec 22, 2008 at 3:45 PM, Jorge Ortiz <jorge [dot] ortiz [at] gmail [dot] com> wrote:
Read my blog post on Manifests: http://scala-blogs.org/2008/10/manifests-reified-types.html

scala> case class Query[T, S](func: T => S)(implicit val t: scala.reflect.Manifest[T], val s: scala.reflect.Manifest[S])
defined class Query

scala> val q = Query((x: Int) => (x + 1).toString)
q: Query[Int,java.lang.String] = Query(<function>)

scala> q.s.toString
res2: java.lang.String = java.lang.String

scala> q.t.toString
res3: java.lang.String = int

--j

On Mon, Dec 22, 2008 at 10:08 AM, Thomas Sant Ana <mailleux [at] gmail [dot] com> wrote:
I have been playing with parametrises type, and every once in a while I run into problems. I may be doing things the wrong way or not supported.
Let me tell the story and then what happens.

I have an actor that has several containers in it. I'd like to send a query function to it, have it map the function on the collections (which depends on the parameter type), and the actor reply a sequence. In essence the messages should be like this:

case class Query[T,S](func:T=>S)
case class Response[S](resp:Seq[S])

And I'd do:

func:Function[A,B]
func2:Fuction[C,D]

a) actor !? Query(func) 

Desired behavior of actor: 

   reply(Response(coll_a.map(func).toSeq))    // where coll_a:List[A]

b) actor !? Query(func2) 

Desired behavior of actor: 

   reply(Response(coll_b.map(func).toSeq))    // where coll_b:List[B]

So actor has to choose coll_a or coll_b using either depdintin on the T of Query[T,S]. I can't seem to find a way to reason on the T information. And erasures will destroy other types of matching like

if(func.isInstanceOf[Function[A,_]])

As an alternative, I have tested this code, I use an enumeration to specify the target of the query. This way I can match the query to the correct collection:

case class Query[T,S](target:Query.target.Value, query:T=>S)
case class Response[S](resp:Seq[S])


However to make my life easiser  I created a function that runs the query and gets the response:


def queryObjs[R](actor:Actor,func:Obj=>R):Seq[R] forSome {type R} = {
  var resp=actor !? Query(Query.target.MapObj,func)
  resp match {
    case Response(s:Seq[R]) => s.asInstanceOf[Seq[R]]
    case _ => throw new Exception("Bad reply from query")
  }
}

The code above works, but I need to create one function for each target. I'd like to create  e generic function query[Q,R], but that fails on run-time.

Is there a more elegante way to get the generic Query/Response model?

Thomas




mailleux
Joined: 2008-08-23,
User offline. Last seen 4 years 7 weeks ago.
Re: Type parametrizations and erasure

I'm backtracking a bit...

On Mon, Dec 22, 2008 at 3:45 PM, Jorge Ortiz <jorge [dot] ortiz [at] gmail [dot] com> wrote:
Read my blog post on Manifests: http://scala-blogs.org/2008/10/manifests-reified-types.html


Manifest really opens up a lot of nice possibilities... But your blogs states:

Starting with version 2.7.2, Scala has added manifests, an undocumented (and still experimental) feature for reifying types. They take advantage of a pre-existing Scala feature: implicit parameters.

My question it this, should I use this in a project or will I run into everchanging interfaces and implementations?

Thomas
Carsten Saager
Joined: 2008-12-19,
User offline. Last seen 42 years 45 weeks ago.
Re: Type parametrizations and erasure
In some other conversation Martin answered it like that:

I suspect Manifests aren't documented because the compiler team wants to be free to experiment with their design and break backwards compatibility without people getting upset (or having justification for getting upset).

It's not even that, even though this would be a reasonable motive. It's simply lack of time. You spend your finite amount of time documenting or developing. As long as the design is not yet fixed, it's better to concentrate on development.

My interpretation is that the design is rather stable already and the team is busy getting it fully implemented - but it is still possible that they'll have to change their approach.

/Carsten

On Tue, Dec 23, 2008 at 5:15 PM, Thomas Sant Ana <mailleux [at] gmail [dot] com> wrote:

I'm backtracking a bit...

On Mon, Dec 22, 2008 at 3:45 PM, Jorge Ortiz <jorge [dot] ortiz [at] gmail [dot] com> wrote:
Read my blog post on Manifests: http://scala-blogs.org/2008/10/manifests-reified-types.html


Manifest really opens up a lot of nice possibilities... But your blogs states:

Starting with version 2.7.2, Scala has added manifests, an undocumented (and still experimental) feature for reifying types. They take advantage of a pre-existing Scala feature: implicit parameters.

My question it this, should I use this in a project or will I run into everchanging interfaces and implementations?

Thomas

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