type equality

Skip to first unread message

Eyal Farago

Jan 20, 2014, 10:32:39 AM1/20/14
to treehugg...@googlegroups.com
I'm using treehugger to implement a code generator, in my generator's code I make a lot of decisions based on types.
It seems that types does not properly implement equality, after some research I came to the conclusion that they 'inherit' this behavior from symbols.

the following scala-ide worksheet illustrates the problem:

val jintSym = RootClass.newClass( "java.lang.Integer")
                                                  //> jintSym  : treehugger.forest.ClassSymbol = java.lang.Integer
val jintTp1  = jintSym.toType             //> jintTp1  : treehugger.forest.Type = java.lang.Integer
val jintTp2  = jintSym.toType             //> jintTp2  : treehugger.forest.Type = java.lang.Integer
val jintTp3 = RootClass.newClass("java.lang.Integer").toType
                                                  //> jintTp3  : treehugger.forest.Type = java.lang.Integer
jintTp1 == jintTp1                        //> res8: Boolean = true
jintTp2 == jintTp2                        //> res9: Boolean = true
jintTp1 == jintTp2                        //> res10: Boolean = true
jintTp3 == jintTp3                        //> res11: Boolean = true
jintTp1 == jintTp3                        //> res12: Boolean = false

as long as I'm using the same symbol instance, the types are equal, once I use two different but equivalent symbol instances, things start to break.
Looking a bit further into the code, it seems that the reason for this is that ClassSymbol and other Symbol classes are not case classes and do not implement hash and equals, since types are build from symbols they 'inherit' this behavior.

Is this by design or just a bug? 
can I expect/contribute a patch for this?


Eugene Yokota

Jan 23, 2014, 1:19:52 AM1/23/14
to treehugg...@googlegroups.com
Hi Eyal,

On Monday, January 20, 2014 10:32:39 AM UTC-5, Eyal Farago wrote:
I'm using treehugger to implement a code generator, in my generator's code I make a lot of decisions based on types.

scalac during compile-time would know the types of each symbol, but treehugger is not a compiler.
The "Type" implemented in treehugger is there mostly to keep symmetry with with scalac and for deriving type-level expressions.
Since I'm not typechecking all the symbols, it didn't occur to me that someone would try to base decisions on treehugger types.
The semantics of the term "java" is not determined until the compiler analyzes all the enclosing blocks, so I think it's fine for two different symbols to produce different types.
Here's an example:

scala> :paste
// Entering paste mode (ctrl-D to finish)

class Foo { type Integer = String }
class Bar { val lang = new Foo() }
val java
= new Bar()

// Exiting paste mode, now interpreting.

defined class Foo
defined class Bar
: Bar = Bar@7e13224e

> val x: java.lang.Integer = "foo"
: java.lang.Integer = foo

So it's by design.
What I think you should do is to make your own symbol table object and keep track of any symbols that appears in multiple places.


Eyal Farago

Jan 23, 2014, 1:49:13 AM1/23/14
to treehugg...@googlegroups.com
Hi Eugene,
thanks for your reply (actually two replies :-))

I understand your counter example, but I don't think it makes sense on the code generation side of things.
I think expecting case class semantics on symbols and types in the context of treehugger is reasonable, i.e.:

RootClass.newClass("aaa") == RootClass.newClass("aaa")
                                                  //> res13: Boolean = false

I find this pretty surprising, I understand that once the compiler sees the aaa symbol its interpretation is context depndent, but it's not so on the code generation side, we're using symbols as pumped-up strings, if we want them to represent a type we make a type out of them, i.e. TYPE_REF( "aaa" ) and if we want them to represent a variable we make a ref out of them: REF("aaa"), so I think it's pretty realistic to expect value semantics out of these things.

I already went for the 'self' symbol table approach, but it poses some costs and complexities on my code, i.e. I've just hit a failing test with the following message:

java.lang.IllegalArgumentException: requirement failed: Iterable[com.actimize.bs.BeanCaseClass] == Iterable[com.actimize.bs.BeanCaseClass]

I think you'd agree with me that this surprising at first, and irritating once you understand what's going on :-)

Reply all
Reply to author
0 new messages