Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

traits and abstract types

Tags:

scala

Assume 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)
}

I then try to add another trait as a mixin, for which I want the return type for copy to be the the appropriate type (meaning that calling copy on the mixin returns a mixin type, by setting B to the appropriate type). I haven't been able to get this to compile, or even to understand where the override keyword should go.

Edited: I have refined 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 an appropriate type B and copy method for DecBase, so that the copy returns a DecBase , and also, why won't this compile?

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

This is something I would have achieved in Java (with some nastiness, using recursive generic types). I'm sure that it's possible to 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
like image 511
user44242 Avatar asked Feb 01 '11 15:02

user44242


People also ask

What is the difference between a trait and an abstract class?

The first difference was already mentioned: classes are limited to inherit from a single abstract class but can inherit from multiple traits. Another important difference is that abstract classes allow specifying constructor parameters. Traits do not allow us to do the same.

Can an abstract class extend a trait?

One of the fundamental differences between a trait and an abstract class is that multiple traits may be used in the inheritance definition of a class, whereas a single abstract class can be extended.

What is trait in spark?

Delta Lake with Apache Spark using Scala A trait encapsulates method and field definitions, which can then be reused by mixing them into classes. Unlike class inheritance, in which each class must inherit from just one superclass, a class can mix in any number of traits.

Is a trait a class?

A Trait is similar to a class, but only intended to group functionality in a fine-grained and consistent way. It is not possible to instantiate a Trait on its own.


1 Answers

I assume your mix in looks something like this

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

I think the override on MyBase is part of the problem. It's unnecessary and confuses the compiler.

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

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

The MixIn.super.copy is a call to the one you want.

You may want to review this page on Scala Class Linearization to understand what happens when you have competing implementations of a method in a type.

Edit: oh this is a completely different problem. It's the val in case MyBase(val rep:String). You can't override a val with a def because a val is assumed to be immutable. You can override a def or var with a val, but not the other way around. Make it:

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

Please include the compiler error next time. It makes it so much easier to see what the problem is.

like image 148
sblundy Avatar answered Oct 14 '22 22:10

sblundy