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

subtype of collection

8 replies
Eric Zbinden
Joined: 2011-10-13,
User offline. Last seen 42 years 45 weeks ago.

Hi,

I'm working on a compiler plug-in for a master semester project. This
plug-in will be inserted after the refcheck phase and use the ast
given by the compiler.

I need to know if the return type of a method definition is an
instance of Collection: Set, List, or whatever collection.
So I check if this return type is a subclass of Traversable: which is
the mother class of all Collection and some others (correct me if I'm
wrong), with the <:< operator. But it seams not working as I
expected... Here is my code:

trait ReturnsTraversable {
self : Definitions => //trait that contains MethodDef declaration
import global._

// Recovers the __symbol__ for the Traversable trait
lazy val traversableTraitSymbol : Symbol =
global.definitions.getClass("scala.collection.Traversable")
// The __type__ of Traversable
lazy val traversableTraitType : Type = traversableTraitSymbol.tpe

def isTraversable(md : MethodDef): Boolean = {
println("Return type : " + md.rettype) //rettype =
d.symbol.tpe.resultType where d is a DefDef given by the compiler
println("Traversable trait : " + traversableTraitType)
println(md.name + "/Traversable:" + md.rettype <:<
traversableTraitType)
md.rettype <:< traversableTraitType
}
}

So if we give to the compiler this simple example of code;
def getElem: List[String] = {
val a = "5"
a :: List("test","8")
}
It should output:
Return type: List[String]
Traversable trait: Traversable[A]
getElem/Traversable: true

But it didn't, I get a "false".
I thing the problem is the generic type A. Could we solve this problem
by testing with a Traversable[Any] ? And if yes, how to parametrise
this generic type? If no, well, is there some trick to solve it ?

Thanks in advance,

Eric

rytz
Joined: 2008-07-01,
User offline. Last seen 45 weeks 5 days ago.
Re: subtype of collection
Hi Eric,
I think looking at the base classes is easier, see below.
Also note that there exists a method named "finalResultType" on types(matters if there are multiple argument lists).
HthLukas


lamppc11:scala luc$ scalaWelcome to Scala version 2.10.0.r25825-b20111013020230 (Java HotSpot(TM) Server VM, Java 1.6.0_26). Type in expressions to have them evaluated.Type :help for more information.
scala> :power** Power User mode enabled - BEEP BOOP SPIZ ** ** :phase has been set to 'typer'.          **** scala.tools.nsc._ has been imported      ** ** global._ and definitions._ also imported **** Try  :help,  vals.<tab>,  power.<tab>    **
scala> val trav = global.definitions.getClass("scala.collection.Traversable") trav: $r.global.Symbol = trait Traversable
scala> val lm = definitions.getModule("scala.collection.immutable.List")lm: $r.global.Symbol = object List
scala> val ap = lm.info.member("apply") ap: $r.global.Symbol = method apply
scala> val resTp = ap.tpe.finalResultTyperesTp: $r.global.Type = List[A]
scala> resTp.baseClasses contains trav res0: Boolean = true



2011/10/13 Eric Zbinden <eric [dot] zbinden [at] japan-impact [dot] ch>
Hi,

I'm working on a compiler plug-in for a master semester project. This
plug-in will be inserted after the refcheck phase and use the ast
given by the compiler.

I need to know if the return type of a method definition is an
instance of Collection: Set, List, or whatever collection.
So I check if this return type is a subclass of Traversable: which is
the mother class of all Collection and some others (correct me if I'm
wrong), with the <:< operator. But it seams not working as I
expected... Here is my code:

trait ReturnsTraversable {
 self : Definitions =>    //trait that contains MethodDef declaration
 import global._

 // Recovers the __symbol__ for the Traversable trait
 lazy val traversableTraitSymbol : Symbol =
global.definitions.getClass("scala.collection.Traversable")
 // The __type__ of Traversable
 lazy val traversableTraitType : Type = traversableTraitSymbol.tpe

 def isTraversable(md : MethodDef): Boolean = {
   println("Return type : " + md.rettype) //rettype =
d.symbol.tpe.resultType where d is a DefDef given by the compiler
   println("Traversable trait : " + traversableTraitType)
   println(md.name + "/Traversable:" + md.rettype <:<
traversableTraitType)
   md.rettype <:< traversableTraitType
 }
}

So if we give to the compiler this simple example of code;
def getElem: List[String] = {
 val a = "5"
 a :: List("test","8")
}
It should output:
Return type: List[String]
Traversable trait: Traversable[A]
getElem/Traversable: true

But it didn't, I get a "false".
I thing the problem is the generic type A. Could we solve this problem
by testing with a Traversable[Any] ? And if yes, how to parametrise
this generic type? If no, well, is there some trick to solve it ?

Thanks in advance,

Eric

adriaanm
Joined: 2010-02-08,
User offline. Last seen 31 weeks 4 days ago.
Re: subtype of collection
hi,
our good friend baseType is probably what you want here: 
tp.baseType(classSym) walks up the subtype lattice, starting in tp, until it finds a type whose symbol equals classSym the important thing to note is that it propagates type parameter instantiations:   (listInt: List[Int]).baseType(SeqClass) == TypeRef(..., SeqClass, List(Int))
to experiment with this further, the REPL is your friend (well, its power mode)
$ scalaWelcome to Scala version 2.9.1.final (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_26).Type in expressions to have them evaluated.Type :help for more information.
scala> :power** Power User mode enabled - BEEP BOOP SPIZ **** :phase has been set to 'typer'.          **** scala.tools.nsc._ has been imported      ** ** global._ and definitions._ also imported **** Try  :help,  vals.<tab>,  power.<tab>    **
scala> import intp.global.definitions._import intp.global.definitions._
scala> 
scala> val xs = List(1,2,3)xs: List[Int] = List(1, 2, 3)
scala> 
scala> intp("xs").tpe.baseType(SeqClass) res0: $r.intp.global.Type = Seq[Int]def methodReturnsTraversable(someMethodType: Type) = someMethodType.finalResultType.baseType(TraversableClass) != NoType // TraversableClass is defined for you in Definitions

Further note that you'll probably need to do pre.memberType(methodSymbol) to compute said someMethodType, as it may depend on the prefix in which the method definition occurs
trait Foo[R] {  def foo: R}
trait Bar extends Foo[Traverable[Any]]
when selected on a Bar, foo returns a Traversable!
cheersadriaan
On Thu, Oct 13, 2011 at 3:46 PM, Eric Zbinden <eric [dot] zbinden [at] japan-impact [dot] ch> wrote:
Hi,

I'm working on a compiler plug-in for a master semester project. This
plug-in will be inserted after the refcheck phase and use the ast
given by the compiler.

I need to know if the return type of a method definition is an
instance of Collection: Set, List, or whatever collection.
So I check if this return type is a subclass of Traversable: which is
the mother class of all Collection and some others (correct me if I'm
wrong), with the <:< operator. But it seams not working as I
expected... Here is my code:

trait ReturnsTraversable {
 self : Definitions =>    //trait that contains MethodDef declaration
 import global._

 // Recovers the __symbol__ for the Traversable trait
 lazy val traversableTraitSymbol : Symbol =
global.definitions.getClass("scala.collection.Traversable")
 // The __type__ of Traversable
 lazy val traversableTraitType : Type = traversableTraitSymbol.tpe

 def isTraversable(md : MethodDef): Boolean = {
   println("Return type : " + md.rettype) //rettype =
d.symbol.tpe.resultType where d is a DefDef given by the compiler
   println("Traversable trait : " + traversableTraitType)
   println(md.name + "/Traversable:" + md.rettype <:<
traversableTraitType)
   md.rettype <:< traversableTraitType
 }
}

So if we give to the compiler this simple example of code;
def getElem: List[String] = {
 val a = "5"
 a :: List("test","8")
}
It should output:
Return type: List[String]
Traversable trait: Traversable[A]
getElem/Traversable: true

But it didn't, I get a "false".
I thing the problem is the generic type A. Could we solve this problem
by testing with a Traversable[Any] ? And if yes, how to parametrise
this generic type? If no, well, is there some trick to solve it ?

Thanks in advance,

Eric

extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.
Re: subtype of collection

Power lovers note: I have this alias

alias scalap='scala -Dscala.repl.power'

the impact of which you can probably infer.

As adriaan gives away with this:

scala> import intp.global.definitions._
import intp.global.definitions._

I still haven't solved the @#%##@(*$!!@# "go away path dependent
types" problem, which more than anything is what keeps me from
documenting it and thus inviting more people to use it. Maybe I can
find time for that one. Ever since I a) defaulted to starting in
phase "typer" and b) fixed type printing so lazy types are not forced
merely by printing them, power mode has become vastly more useful.

adriaanm
Joined: 2010-02-08,
User offline. Last seen 31 weeks 4 days ago.
Re: subtype of collection
yeah, i got tired of typing that import, so I decided to automate it: https://github.com/adriaanm/scala-dev/commit/bf57e19261549ff93d3e51dc7115b1837ed239a2 it may not bring us world peace, but the common use cases should work
as long as everybody agrees on using intp.global, we should be fine, right?

On Thu, Oct 13, 2011 at 5:16 PM, Paul Phillips <paulp [at] improving [dot] org> wrote:
Power lovers note: I have this alias

 alias scalap='scala -Dscala.repl.power'

the impact of which you can probably infer.

As adriaan gives away with this:

scala> import intp.global.definitions._
import intp.global.definitions._

I still haven't solved the @#%##@(*$!!@# "go away path dependent
types" problem, which more than anything is what keeps me from
documenting it and thus inviting more people to use it.  Maybe I can
find time for that one.  Ever since I a) defaulted to starting in
phase "typer" and b) fixed type printing so lazy types are not forced
merely by printing them, power mode has become vastly more useful.

extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.
Re: subtype of collection

On Thu, Oct 13, 2011 at 8:32 AM, Adriaan Moors wrote:
> yeah, i got tired of typing that import, so I decided to automate
> it: https://github.com/adriaanm/scala-dev/commit/bf57e19261549ff93d3e51dc7115b1837ed239a2
> it may not bring us world peace, but the common use cases should work
> as long as everybody agrees on using intp.global, we should be fine, right?

The big obstacle (to this and many other things) is that I inherited a
design where intp is a var and can be cleared and reset. That means
it's not stable, so if you ever want to refer to its types you have to
say "val intp = ILoop.this.intp" and work from that. So we can't even
all agree on intp.

It is not amenable to simple fixage.

extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.
Re: subtype of collection

On Thu, Oct 13, 2011 at 8:32 AM, Adriaan Moors wrote:
> yeah, i got tired of typing that import, so I decided to automate
> it: https://github.com/adriaanm/scala-dev/commit/bf57e19261549ff93d3e51dc7115b1837ed239a2
> it may not bring us world peace, but the common use cases should work
> as long as everybody agrees on using intp.global, we should be fine, right?

After chasing my tail all morning, I come dangerously close to losing
it at this point. It's a freaking cast, scalac. ACCEPT.

[scalacfork] /scala/trunk/src/compiler/scala/tools/nsc/interpreter/ILoop.scala:93:
error: type mismatch;
[scalacfork] found : interpreter.this.IMain{
val global: ILoop.this.global.type}
[scalacfork] required: interpreter.this.IMain{
val global: ILoop.this.global.type}
[scalacfork] outer.intp.asInstanceOf[IMain { val global:
ILoop.this.global.type }]
[scalacfork] ^

Now I remember why I keep not putting the nail in that coffin.

Eric Zbinden
Joined: 2011-10-13,
User offline. Last seen 42 years 45 weeks ago.
Re: subtype of collection

Thanks for your answer. :)

I'm wondering (just for curiosity), which method should I use to
retrieve the inside type of a generic class type ? i.e. If I have an
instance of type "List[String]", how to obtain the "String" alone ?

extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.
Re: Re: subtype of collection

On Mon, Oct 17, 2011 at 5:50 AM, Eric Zbinden
wrote:
> I'm wondering (just for curiosity), which method should I use to
> retrieve the inside type of a generic class type ? i.e. If I have an
> instance of type "List[String]", how to obtain the "String" alone ?

scala> appliedType(ListClass.typeConstructor, List(StringClass.tpe))
res0: $r.intp.global.Type = List[String]

scala> res0.typeArgs
res1: List[$r.intp.global.Type] = List(String)

scala> res0.typeConstructor
res2: $r.intp.global.Type = List

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