Traits and Abstract Types

Suppose I have a base class

abstract class Base { type B<: Base def rep:String def copy:B } class MyBase(override val rep:String) extends Base { type B = MyBase override def copy = new MyBase(rep) } 

Then I try to add another attribute as mixin, for which I want the return type for the copy to be the appropriate type (this means that the call copy on mixin returns the mixin type, setting B to the appropriate type), I was unable to get this to compile or even understand where the override keyword should run.

Edited: I clarified the example

 abstract class Base { type B <: Base def rep:String def copy:B } class MyBase(val rep:String) extends Base { type B = MyBase def copy = new MyBase(rep) } trait DecBase extends Base { abstract override def rep = "Rep: "+super.rep } 

My question is how do I declare a suitable type B and copy method for DecBase, so that the copy returns DecBase, and also, why does not this compile?

 println(((new MyBase("ofer") with DecBase)).rep) 

This is what I would achieve in Java (with some muck using recursive generic types). I'm sure you can do something nicer in Scala.

Edit

Using

 trait DecBase extends Base { override type B = DecBase abstract override val rep= "Dec:"+super.rep abstract override def copy = new MyBase(rep) with DecBase } 

I get the following compiler errors

 error: overriding type B in class MyBase, which equals com.amadesa.scripts.MyBase; type B in trait DecBase, which equals com.amadesa.scripts.DecBase has incompatible type println(((new MyBase("ofer") with DecBase)).rep) error: overriding type B in class MyBase, which equals com.amadesa.scripts.MyBase; type B in trait DecBase, which equals com.amadesa.scripts.DecBase has incompatible type abstract override def copy = new MyBase(rep) with DecBase 
+6
scala
source share
3 answers

I guess your mix looks something like this.

 trait MixIn extends Base { override B = MixinBase override def copy = new MixinBase(rep) } 

I think override on MyBase is part of the problem. This is unnecessary and confuses the compiler.

If copy on Base actually has an implementation, making override necessary, you need to tell the compiler which method to use. If this is not obvious, it throws up its hands and causes an error. Try it.

 val b = new MyBase(rep) with MixIn { override def copy = MixIn.super.copy } 

MixIn.super.copy is the call of the one you want.

You can view this Scala Linearization of Classes page to see what happens when you have competing method implementations in a type.

Edit: oh, this is a completely different issue. This is the val value in case MyBase(val rep:String) . You cannot override val with def because val is considered immutable. You can override def or var with val, but not vice versa. Do it:

 trait DecBase extends Base { abstract override val rep = "Rep: "+super.rep } 

Next time indicate a compiler error. This makes it much easier to understand what the problem is.

+2
source share

I think this has something to do with val rep in the MyBase class. You must define MyBase abstract if you are not going to implement def rep .

Here is a working example:

 abstract class Base { type B <: Base def rep:String def copy: B } class MyBase(val repVal: String) extends Base { type B = MyBase def rep = repVal def copy = new MyBase(repVal) } trait DecBase extends Base { abstract override def rep = "Rep: " + super.rep } println(((new MyBase("ofer"))).rep) // prints: ofer println(((new MyBase("ofer") with DecBase)).rep) // prints: Rep: ofer 

Hope this helps.

0
source share

So, I understand, the goal is to be able to:

 val myBase: MyBase = new MyBase("alone") val myBaseCopy: MyBase = myBase.copy val decBase: DecBase = new MyBase("mixed") with DecBase val decBaseCopy: DecBase = decBase.copy 

Allows you to rewrite code to use type restrictions instead of equality in type declarations (and also fix the mismatch between val rep and def rep , which hides some other compiler errors):

 abstract class Base { type B <: Base def rep: String def copy: B } class MyBase(_rep: String) extends Base { type B <: MyBase def rep = _rep def copy = new MyBase(rep) } trait DecBase extends Base { override type B <: DecBase override abstract def rep = "Rep: " + super.rep } 

Now it is said that MyBase.copy should return MyBase or a subclass, and DecBase.copy should return a DecBase or subclass. I believe what you want, right? Now the resulting compiler error is clear:

 temp.scala:10: error: type mismatch; found : this.MyBase required: MyBase.this.B def copy = new MyBase(rep) ^ one error found 

So, you are returning MyBase , but you really need to return a subclass, for example. you want to return new MyBase(rep) with DecBase instead of new MyBase(rep) , but only when your object was declared as new MyBase(...) with DecBase . I don’t know how to do this, perhaps you can see the addition of the attribute after the object has been created .

0
source share

All Articles