I would like to define an abstract recursive data structure with an abstract type.
Something like this :
case class ParentA( name : String, children : List[ParentA] ) extends Parent {
type PARENT = ParentA
}
case class ParentB( name : String, children : List[ParentB] ) extends Parent {
type PARENT = ParentB
}
sealed abstract class Parent {
// we'd like to Define Parent as a PARENT
// something like:
// this : PARENT =>
type PARENT <: Parent
val name : String
val children : List[PARENT]
def findParent(name:String) : Option[PARENT] = {
if( name == this.name ) {
Some(this) // ouch
} else {
// re-ouch
children.flatMap( f => f.findParent(name) )
}
}
}
val a2a : ParentA = ParentA("a",List(ParentA("a1",Nil),ParentA("a2",List(ParentA("a2a",Nil))))).findParent("a2a").get
Of course this won't compile, because the compiler cannot guess that Parent.this is a PARENT .
error: type mismatch;
found : Parent.this.type (with underlying type this.Parent)
required: Parent.this.PARENT
Some(this)
And also
error: type mismatch;
found : List[Parent.this.PARENT#PARENT]
required: Option[Parent.this.PARENT]
children.flatMap( f => f.findParent(name) )
I can get around it by casting here and there but it would be better to be able to tell the compiler that Parent is a PARENT.
Or maybe i'm missing something :)
Edit - Generics
I forgot to mention that Generics are not an option. This example is actually a simplified version of a more subtle problem. Using generics will lead to a quadratic growth of the program. Here is a link explaining why generics are not always a viable alternative : Scala: Abstract types vs generics.
Basically i'm better off using abstract types - or even neither abstract types nor generics - and casting.
The same idea as mentioned by #Debilski, but no extra type parameter:
case class ParentA(name: String, children: List[ParentA]) extends Parent[ParentA]
case class ParentB(name: String, children: List[ParentB]) extends Parent[ParentB]
sealed abstract class Parent[P <: Parent[P]] { this: P =>
def name: String
def children: List[P]
def findParent(name: String): Option[P] =
if (name == this.name) Some(this)
else children.flatMap(_.findParent(name)).headOption
}
By the way, use defs instead of vals for abstract members. They allow more flexibility while implementing them in subclasses.
Only for reference. sschaef has a better way to do it.
This compiles using the Scala CRTP and self-types.
case class ParentA(name : String, children : List[ParentA]) extends Parent[ParentA]
case class ParentB(name : String, children : List[ParentB]) extends Parent[ParentB]
sealed abstract class Parent[T] { this : T =>
type PARENT = Parent[T] with T
val name : String
val children : List[PARENT]
def findParent(name:String) : Option[PARENT] = {
if( name == this.name ) {
Some(this)
} else {
children.flatMap( f => f.findParent(name) ).headOption
}
}
}
val a2a : ParentA = ParentA("a",List(ParentA("a1",Nil),ParentA("a2",List(ParentA("a2a",Nil))))).findParent("a2a").get
Related
I don't know if there's a way to do this, but I want to be able to specify that a set of case classes all share a parameter (so I can access it without pattern matching).
EDIT: After some help I have
abstract class Test(val termName : String)
case class TestOne(value : Int, name : String = null) extends Test(name)
case class TesTwo(otherValue : Boolean, name : String = null) extends Test(name)
Which is almost exactly what I want, though it would be nice to get rid of the ugliness of having both name and termName.
though it would be nice to get rid of the ugliness of having both name and termName.
Just make it a normal member of the supertype (which can easily be a trait), not a constructor parameter:
trait Test {
val name : String
}
case class TestOne(value : Int, name : String = null) extends Test
case class TestTwo(otherValue : Boolean, name : String = null) extends Test
(The standard Scala style is name: String, no space before :.)
If every implementation should have a separate, distinct implementation, declare abstract member and implement it in children:
abstract trait NamedCaseClass {
def name: String
}
case class OneCase(number : Int) extends NamedCaseClass {
override def name: String = "OneCase"
}
case class OtherCase(truth : Boolean) extends NamedCaseClass {
override def name: String = "OtherCase"
}
If all implementations could just use some value that you can calculate on creation, you can use abstract class constructor:
abstract class NamedCaseClass(val name: String)
case class OneCase(number : Int) extends NamedCaseClass("OneCase")
case class OtherCase(truth : Boolean) extends NamedCaseClass("OtherCase")
If you have a sealed hierarchy you could also define it like this:
sealed trait NamedCaseClass {
def nameOpt: Option[String] = this match {
case OneCase(number) => Some(name.toString)
case OtherCase(_) => None
}
}
case class OneCase(number : Int) extends NamedCaseClass
case class OtherCase(truth : Boolean) extends NamedCaseClass
Which one is more convenient pretty much depend on if you have a sealed hierarchy or open, if you can calculate value on creation or is this something more complicated that would work better as a method.
I discovered that using abstract types affects the scala compiler ability to detect overrides and it interprets seemingly correct code as erroneous.
trait I {
type T
def doThings(t : T) : Unit
}
type IT[X] = I { type T = X}
trait A extends I {
override type T = AnyRef
def doThings(t : T) : Unit = println("A")
}
trait Z[X] extends I { this : IT[X] =>
abstract override def doThings(t : T) : Unit = {
println("Z")
super.doThings(t)
}
}
object Use {
val az = new A with Z[AnyRef] {}
}
The scala compiler fires such error:
OverloadAbstract.scala:44: error: object creation impossible, since method doThings in trait Z of type (t: this.T)Unit is marked `abstract' and `override', but no concrete implementation could be found in a base class
val az = new A with Z[AnyRef] {}
What is the proper way to express such relations between trait mixing and implementation?
For the comparison that code works fine:
trait I {
def doThings() : Unit
}
class A extends I {
def doThings() : Unit = println("A")
}
trait Z extends I {
abstract override def doThings() : Unit = {
println("Z")
super.doThings()
}
}
object Use {
val az = new A with Z {}
}
The real use case is to implement a forwarder for the akka.event.EventBus:
object PartialEventBus {
type ApplyEvent[E] = EventBus { type Event = E }
}
trait ForwardEventBus[E] extends EventBus { this : PartialEventBus.ApplyEvent[E] =>
def relay : PartialEventBus.ApplyEvent[E]
abstract override def publish(event : Event) : Unit = {
relay.publish(event)
super.publish(event)
}
}
Type parametrization for the ForwardEventBus is needed for compiler to match object-wide this.Event type with external relay.Event type. Compiler would fail without such hint because of scala's path-dependent types restrictions.
Perhaps I'm confused, shouldn't the question be "Why does abstract override succeed?" Section 5.2.4 of the spec covers abstract override, and it says, "The override modifier has an additional significance when combined with the abstract modifier. That modifier combination is only allowed for value members of traits."
I hope a language lawyer can weigh in, but it looks like this should not be legal.
I have the following trait hierarchy. TraitA is the root trait, and given that I want my data structures to be immutable, the function commonUpdateFunction() has a generic return type. I am not sure if this is the best way. I have two other traits that extend it, adding two other functions. Some classes extend one, some classes extend the other, but some classes need to extend both.
However, I am now running into a problem where because of that generic type thing I am getting illegal inheritance, when in reality I am only doing it to get the right type when updating the data structure to a new one.
Furthermore it seems I cannot pass TraitA as a parameter because of this generic type.
trait TraitA[T <: TraitA[T]]
{
self : T =>
def commonUpdateFunction() : T
}
trait TraitB extends TraitA[TraitB]
{
def someFunctionB() : Integer = { /// some code }
}
trait TraitC extends TraitA[TraitC]
{
def someFunctionC() : Unit = { /// some code }
}
class ClassB extends TraitB
{
def commonUpdateFunction() : ClassB = { /// some code }
}
class ClassC extends TraitC
{
def commonUpdateFunction() : ClassC = { /// some code }
}
class ClassA extends TraitB with TraitC //**this causes illegal inheritance**
{
def commonUpdateFunction() : ClassA = { /// some code }
}
What is the right way to achieve this inheritance on 2 traits while at the same time having immutable updating of data structures with the right types?
Type parameters aren't your problem here, the problem is that ClassA tries to mix in three copies of commonFunction(), which differ only by return type:
class ClassA extends TraitB with TraitC {
def commonFunction() : ClassA = { /// some code }
def commonFunction() : ClassB = { /// some code }
def commonFunction() : ClassC = { /// some code }
}
Although the JVM does allow overloading on return type, it isn't permitted at compile time - there's just too much chance for confusion (especially if type inference is involved).
The solution is often to use f-bounded polymorphism (as you did with commonUpdateFunction()), but it's impossible to show how to do that here given that all your commonFunction() definitions are concrete.
It would help a lot to see more "real" code!
UPDATE: Based on new information from the comments.
Instead of a type parameter you might find life easier with an abstract type member. Using Repr (for "Repr"esentation) is a common enough convention and used in the collections lib; make sure that this abstract type member has a bound!
Stick the other common attributes in here as well:
trait Employee {
type Repr <: Employee
def name : String
def id : Int
def withName(name: String) : Repr
def withId(id: Int) : Repr
}
sub-traits follow a similar pattern. There's no need to re-declare other abstract members that keep their signature. You can also introduce other members as you refine the types here.
trait ManagingEmployee extends Employee {
type Repr <: ManagingEmployee
def numberOfReports: Int
def withNumberOfReports(x: Int) : Repr
}
trait SkilledEmployee extends Employee {
type Repr <: SkilledEmployee
def skill: String
}
Now make the leaf nodes of our type tree concrete. case classes work well here, though there will sadly be some duplication (macros could possibly help, but that's a different question).
Note how name and id are made concrete by the class params, the Repr type is made explicit via the = sign, and the abstract methods have to be explicitly re-defined in each leaf class:
case class HrManager(
name : String,
id : Int,
numberOfReports : Int
) extends ManagingEmployee {
type Repr = HrManager
def withName(name: String) = this.copy(name = name)
def withId(id: Int) = this.copy(id = id)
def withNumberOfReports(x: Int) = this.copy(numberOfReports = id)
}
case class Technician(name: String, id: Int) extends SkilledEmployee {
type Repr = Technician
def withName(name: String) = this.copy(name = name)
def withId(id: Int) = this.copy(id = id)
val skill = "programming"
}
case class TechnicalManager(
name : String,
id : Int,
numberOfReports : Int
) extends SkilledEmployee with ManagingEmployee {
type Repr = TechnicalManager
def withName(name: String) = this.copy(name = name)
def withId(id: Int) = this.copy(id = id)
def withNumberOfReports(x: Int) = this.copy(numberOfReports = id)
val skill = "software architecture"
}
I have this:
abstract class Issue( ... ) extends Ordered[Issue] {
def compare(o : Issue) = due.compare(o.due)
def render() : String
}
case class Task( ..., subtasks : scala.List[Subtask]) extends Issue( ... ) {
def render() = ...
}
case class Subtask( ..., parent : String ) extends Issue( ... ) {
override def compare(o:Subtask) = {
... delegate to some field's compare function ...
}
def render() = ...
}
I want to use
val l1 : List[Task] = tasks.sorted
val l2 : List[Subtask] = subtasks.sorted
But it does not work:
error: diverging implicit expansion for type scala.math.Ordering[this.Subtask]
starting with method ordered in trait LowPriorityOrderingImplicits
,subtasks.sorted.map(_.render()).mkString(" | ")).mkString(" | ")
How do I write this aglebraic type with different orderings for the individual constructors ?
In Subtask you're not overriding the parent method correctly, because they take different parameter types. Try this:
case class Subtask( ..., parent : String ) extends Issue( ... ) {
override def compare(o: Issue) = o match {
case x: Subtask => ... // your new comparison
case x => super.compare(x)
}
...
}
However, when sorting, we need an Ordering[Issue], not an Ordering[Subtask], because the compare method takes an Issue.
So to sort a List[Subtype], for the compiler to get the correct Ordering object, it needs to be typed as a List[Issue] rather than List[Subtask].
So add a type annotation where you declare subtasks, or upcast it thus when calling:
(subtasks: List[Issue]).sorted
Have you tried passing the subclass as type parameter to the abstract superclass? Something like this:
abstract class Issue[I <: Issue[I]](...) extends Ordered[I] {
def compare(o: I) = due.compare(o.due)
}
case class Task(...) extends Issue[Task](...)
case class Subtask(...) extends Issue[Subtask](...)
In Scala, how can i add a container trait (like Traversable[Content]) to another one that extends the container (and thus has limited visibility of its content ?
For example, the code below tries to define a trait WithIter for a container requiring Traversable (of course, i have in fact other things in Container).
import scala.collection._
trait Container {
type Value
}
trait WithIter extends Container with immutable.Traversable[Container#Value]
class Instance extends WithIter {
type Value = Int
def foreach[U](f : (Value) => (U)) : Unit = {}
}
Compiler (scalac 2.8.0.Beta1-RC8) finds an error:
error: class Instance needs to be abstract, since method foreach in trait GenericTraversableTemplate of type [U](f: (Container#Value) => U)Unit is not defined
Is there any simple way?
class Instance extends WithIter {
type Value = Int
def foreach[U](f : (Container#Value) => (U)) : Unit = {}
}
If you do not specify OuterClass# when speaking of an inner class, then this. (ie, instance-specific) will be assumed.
Why do you use an abstract type? Generics are straightforward:
import scala.collection._
trait Container[T] {}
trait WithIter[T] extends Container[T] with immutable.Traversable[T]
class Instance extends WithIter[Int] {
def foreach[U](f : (Int) => (U)) : Unit = {println(f(1))}
}
new Instance().foreach( (x : Int) => x + 1)