Ordering with algebraic types in scala - scala

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](...)

Related

How can I reference a companion object's method in a generic class?

So I am a bit new to scala.
How does one write scala code to reference a method from case class's companion object in a generic fashion? I have tried a couple of different approaches and can't seem to find one that works.
Below is some sample code that works, but I have to manually build each subclass.
For example:
class One extends Act[LetterA] {
val intro = LetterA.sayhi
}
I would much rather do something like:
class AllOfThem[T <: LettersClass, S <: LettersSingleton] extends Act[T] {
val intro = S.sayhi
}
but I can't seem to find syntax that works or will compile. What is the proper way to do this, or am I looking for something that is not supported in the language? I recognise I am probably a little off on how I am structuring my classes and traits, but I am not sure how to best tackle this desired behaviour.
Additionally, is there a way to something similar to what I have commented out in the method 'actionTwo' in the Act class?
Sample Code listing:
trait LettersSingleton {
def sayhi() : String
}
trait LettersClass {
val id : Int
}
// trait Letters extends LettersClass with LettersSingleton { }
object LetterA extends LettersSingleton {
def sayhi = "Hi I am A"
}
object LetterB extends LettersSingleton {
def sayhi = "Hi I am B"
}
case class LetterA( val id : Int ) extends LettersClass { }
case class LetterB( val id : Int, val name:String ) extends LettersClass { }
abstract class Act[ T <: LettersClass ] {
val intro : String
def actionOne( a : T ) = {
println( a.id + " is my id" )
}
def actionTwo() = {
// println( T.sayhi )
}
}
class One extends Act[LetterA] {
val intro = LetterA.sayhi
}
class Two extends Act[LetterB] {
val intro = LetterB.sayhi
}
So you can't do exactly what you want, but you can get very close with the commonly used typeclass pattern:
//add a type parameter, now you have a typeclass
trait LettersSingleton[T] {
def sayhi() : String
}
//LettersClass stays the same
object Implicits {
//implicit classes/objects have to go inside an object
//create typeclass instances as implicit objects
implicit object LetterASingleton extends LettersSingleton[LetterA] {
def sayhi = "Hi I am A"
}
implicit object LetterBSingleton extends LettersSingleton[LetterB] {
def sayhi = "Hi I am B"
}
}
import Implicits._
//add an implicit parameter to the class
abstract class Act[ T <: LettersClass ](implicit singleton: LettersSingleton[T]) {
def actionTwo() = {
println( singleton.sayhi )
}
}
(new Act[LetterA]).actionTwo() //prints "Hi I am A"
(new Act[LetterB]).actionTwo() //prints "Hi I am B"
So basically what happens is any time you create a new Act[T], the compiler is going to try to fill in the implicit parameter for you by looking for any implicit objects or vals of the correct type in scope. So
val a = new Act[LetterA]
will actually become
val a = new Act[LetterA](LetterASingleton)
You'll notice that the singletons are no longer the companion objects of the case classes, which is fine. You have to define a trait regardless, so it doesn't make much different whether it's the companion object or some other object that implements it.

Cast Type Alias to generic type without the use of package object

I am at the moment writing a repository actor that works similar to the usual List collection but without shifting elements one position to the left on removal. Hence the use of an array.
The only types that this repository will tolerate are those that extend both an Actor and the Indexable type. I want to make use of a Type Alias as a shortcut for this type condition. How do I cast a Type Alias to a generic type inside a class declaration without using a package object as demonstrated below? (See Line #2 and Line #7)
package object model {
type Mob = Actor with Indexable
object IndexableRepository {
def create[T <: Mob](capacity : Int) = Props(new IndexableRepository[T](capacity))
}
final class IndexableRepository[T <: Mob](val capacity : Int) extends Actor {
private var indexables = new Array[Mob](capacity)
def receive : Actor.Receive = {
case _ => unhandled()
}
private def findAvailable(indexables : Seq[Mob]) = {
(0 to indexables.size) find { idx => indexables(idx) == null }
}
}
}
How about declaring the type alias in the companion object:
import akka.actor.{Props, Actor}
import IndexableRepository._
final class IndexableRepository[T <: Mob](val capacity : Int) extends Actor {
private var indexables = new Array[Mob](capacity)
def receive : Actor.Receive = {
case _ => unhandled()
}
private def findAvailable(indexables : Seq[Mob]) = {
(0 to indexables.size) find { idx => indexables(idx) == null }
}
}
object IndexableRepository {
type Mob = Actor with Indexable
def create[T <: Mob](capacity : Int) = Props(new IndexableRepository[T](capacity))
}
Though, I think Actor instances are not meant to be referenced anywhere. Storing them in a collection looks somewhat suspicious.

Add a trait to parametric type in a class

I have a library where an abstract class Base[T] is over a type T supplied by the user. There are many specific Base[T] sub-classes, some are over types T and S, like Specific[T, S], but this is irrelevant. The user might specify any T of course while creating and instance, but I want to treat it as T with a trait AdditionalAbilities or in other words I want to 'gift' the user's type with AdditionalAbilities. How can I do that in Scala? I hope the title is correct for this question.
Example (might not be syntactically correct)
class Specific[T **with trait Additional**]() extends Base[T](){
def doSomething() : T = {
val something = new T()
something.ability(2)
println(something.additional)
something
}
}
trait Additional{
var additional : Integer
def ability(i : Integer) : Unit = {
additional = i
}
}
Would work with any T.
When you define a parametric class you can require the parameter type to descend from a certain type:
trait AdditionalAbilities {
def doStuff(): Unit = println("Hey There")
}
object NoAbility extends AdditionalAbilities {
override def doStuff(): Unit = ()
}
abstract class Base[T] { ... }
class Specific[T <: AdditionalAbilities] extends Base[T] {
def f(t: T): Unit = t.doStuff()
}
Then when you try to instantiate a Specific type:
scala> new Specific[Int] {}
<console>:13: error: type arguments [Int] do not conform to class Specific's type parameter bounds [T <: AdditionalAbilities]
scala> val b = new Specific[NoAbility.type] {}
b: Specific[NoAbility.type] = $anon$1#517cd4b
scala> b.f(NoAbility)
//did nothing
Also, if you want to add a behaviour to an existing concrete class, you can do so at the time of instantiation:
trait CoolAbilities { def doStuff(): Unit = println("Hey there") }
class A { }
scala> val a = new A with CoolAbilities
a: A with CoolAbilities = $anon$1#6ad3381f
scala> a.doStuff()
Hey there
Perhaps implicit classes could help? Implicit classes allow you to add functionality to an existing type without needing to modify the existing type, or be the one instantiating it (so that you could mix in a trait).
The following compiles, and prints: 3
class Specific[T] {
implicit class TAdditional(t: T) {
var additional: Integer = 0
def ability(i: Integer) = {
additional = i
}
}
def doSomething(t: T) = {
doSomethingAdditional(t)
}
private def doSomethingAdditional(t: TAdditional) = {
t.ability(3)
println(t.additional)
}
}
val s = new Specific[Int]
s.doSomething(5)
Note: We need to do something to make sure we are accessing the same instance
of TAdditional, that's why I made the private doSomethingAdditional method that takes a TAdditional as an argument. If we call ability and additional in 'doSomething', separate instances of TAdditional would be created when we try to access #ability and #additional, and '0' would be printed.

Scala List with abstract class type and accessing to child

I create one abstract class and two real class
abstract class ProcElems {
def invoke()
}
class Brick(title: String) extends ProcElems {
def invoke {
println("invoked brick")
}
}
class Block(title:String) extends ProcElems {
def block_method = println("1")
override def invoke {
println("invoked block")
}
}
Now i defining a List with Abstract class type
and add to it some object like brick and block types
val l: List[ProcElems] = List(Title: block, Title: brick, Title: block)
and when i try invoke block_method on first element it gives me error, because ProcElems doesnt have that method. But when i do
l.head.getClass #/ gives the real(non abstract) class Block
Question: How i can call block_method on list element with abstract class type?
Similar to wheaties' answer, you can use collect with a PartialFunction to get a collection containing only those elements where the partial function applies:
scala> val l: List[ProcElems] = List(new Brick("brick"), new Block("block1"), new Block("block2"))
scala> val blocks = l.collect { case block: Block => block }
blocks: List[Block] = List(Block#d14a362, Block#45f27da3)
You now have a List[Block] that you can use as you see fit:
scala> blocks.head.block_method
1
scala> blocks.foreach(_.block_method)
1
1
You a PartialFunction aproach:
myList.foreach{
case x:Block => x.block_method
case _ =>
}

self annotation using abstract type

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