Hi -
I am trying to learn Scala and have hit upon the wall while trying to understand abstract data types .. I have the following snippet : object ShapeTest extends Application { class Point(x : int, y : int) { override def toString() = "[" + x + "," + y + "]" } abstract class Shape { def draw() : unit } class Line(s : Point, e : Point) extends Shape { def draw() : unit = { Console.println("draw line " + s + "," + e) } } abstract class Foo { type T <: Object def show(o : T) : unit def print() : unit = {Console.println("in Foo")} } abstract class ShapeFoo extends Foo { type T <: Shape def show(o : T) : unit = { o.draw() } override def print() : unit = {Console.println("in ShapeFoo")} } class LineFoo extends ShapeFoo { type T = Line override def print() : unit = {Console.println("in LineFoo")} } val p1 = new Point(1,4) val p2 = new Point(12, 28) val l1 = new Line(p1, p2) val l = new ShapeFoo{ // ** // type T = Line // ** // override def print() : unit = {Console.println("in LineFoo")} // ** // } // ** // l.show(l1) // ** // } When I compile the above program, I get the following error : D:\scala-2.1.0\dg>scalac shape.scala shape.scala:43 error: type mismatch; found : ShapeTest.this.Line required: ShapeTest.this.l.T l.show(l1) ^ one error found But when I replace the last 5 lines (marked with // ** //) with : val l = new LineFoo() l.show(l1) the program compiles fine. All I want to do is use the anonymous class with inline redefinition of the abstract type. Any help will be appreciated. BTW I am using Scala 2.1.0. Thanks. - DG |
Dear Debashish:
Thanks for your mail. The problem in your code is in the last lines: val l = new ShapeFoo{ type T = Line override def print() : unit = {Console.println("in LineFoo")} } l.show(l1) Here, the type of `l' is just ShapeFoo, which means that the type binding type T = Line is forgotten. This is a consequence of the typing rules for anonymous instance creation expressions and blocks (Section 6.7 and 6.8 of the Spec). You can recover the missing type information in two ways. Either you turn `l' into an Object: object l extends ShapeFoo{ type T = Line override def print() : unit = {Console.println("in LineFoo")} } l.show(l1) Or you add the type alias implicitly as a refinement: val l: ShapeFoo { type T = Line } = new ShapeFoo{ type T = Line override def print() : unit = {Console.println("in LineFoo")} } l.show(l1) That said, I think the Scala spec might be generalized a bit in the future order to allow code like the one you wrote. I'll keep it in my mind. Cheers -- Martin |
Martin Odersky <martin.odersky <at> epfl.ch> writes:
> > Dear Debashish: > > Thanks for your mail. The problem in your code is in the last lines: > <snippet removed> > ... > ... > That said, I think the Scala spec might be generalized a bit in the > future order to allow code like the one you wrote. I'll keep it in my mind. > > Cheers > > -- Martin > > Dear Martin - Thanks for the clarification. But still one question confuses me. A similar code (please see the fragment below) compiles OK in Scala 1.4.0.4, but of course gives the same error (which I mentioned in my previous post) in Scala 2.1.2. Has there been any change in typing rules for anonymous instance creations in Scala 2 ? object GenericsTest with Application { abstract class Sum { type t; def add(x: t, y: t): t = x; } object intSum extends Sum { type t = Int; override def add(x: Int, y: Int): Int = x + y; } class ListSum[a] extends Sum { type t = List[a]; override def add(x : List[a], y : List[a]) : List[a] = x ::: y; } val i = new Sum{type t = Int}.add(12, 16); Console.println(i); } Best Regards. - DG |
Debasish Ghosh wrote:
> Dear Martin - > > Thanks for the clarification. But still one question confuses me. > A similar code (please see the fragment below) compiles OK in Scala 1.4.0.4, > but of course gives the same error (which I mentioned in my previous post) in > Scala 2.1.2. > Has there been any change in typing rules for anonymous instance creations in > Scala 2 ? > > type member definitions would be added as a refinement of the type of an anonymous instance creation but value members would not. The new version first erred on the conservative side -- by eliminating all members in a refinement unless they were given explicitly. But that's not very intuitive, it seems. I have now verified that nothing in our codebase would break if we generalize the rule, admitting all members in the refinement. Looking at it from the language definition side, here is the issue: Let's suppose we have a class class Foo { type T; val x: Any } An anonymous instance creation new Foo { type T = int; val x = 1 } is seen as equivalent to the block { class $anon extends Foo { type T = int; val x = 1 }; new $anon } What should the type of that block be? Normally, it would be $anon, except that this is illegal because the name $anon is not visible outside the block. The current spec says it is instead the parent type of $anon, which is Foo. Unfortunately, this forgets about the overriding definitions in the anonymous class. The proposed revised spec would say that the type of the block is the least proper supertype of the anonymous class. This happens to be the type Foo { type T = int; val x: int } which is what we want, I think. The change will probably be rolled into the next Scala release (2.1.4). Thanks for bringing this up! -- Martin |
Free forum by Nabble | Edit this page |