Reputation: 1227
When I compile following code with Scala 2.11.1 and Akka 2.3.4, I get Error:
Error:(24, 35) Parameter type in structural refinement may not refer to an abstract type defined outside that refinement
def behavior(list: List[T], ele: T):Receive={
^
Error:(24, 35) Parameter type in structural refinement may not refer to a type member of that refinement
def behavior(list: List[T], ele: T):Receive={
^
The code:
package exp
import akka.actor.{ActorSystem, Props, Actor}
trait myTrait[T <: myTrait[T]]{
def computeDistance(that: T): Double
}
class otherClass[T <: myTrait[T]](){
def func(data: List[T]):List[String]={
val system = ActorSystem()
system.actorOf(Props(new Actor{
case object START
case class Job(e1: T, e2: T)
def receive = {
case START =>
context become behavior(data.tail, data.head)
}
def behavior(list: List[T], ele: T):Receive={
case _ =>
sender ! Job(list.head, ele)
context become behavior(list.tail, ele)
}
}))
List.empty[String]
}
}
object Test {
class myClass(val x:Double) extends myTrait[myClass]{
override def computeDistance(that: myClass): Double = this.x - that.x
}
def main(args: Array[String]){
val fc = new otherClass[myClass]()
fc.func(List.empty[myClass])
}
}
The reason I define myTrait as myTrait[T <: myTrait[T]] is that I want subclass of myTrait can override computeDistance method with subclass argument. Follows this post.
otherClass provides a method func to produce some computation on a list of myClass instances. (Actually the above code is an abstraction of my need.)
Adding generic type on behavior can eliminate the above error, but it will cause new error.
def behavior[S](list: List[T], ele: S):Receive={
case _ =>
sender ! Job(list.head, ele)
context become behavior(list.tail, ele)
}
Then, in Job(list.head, ele), the ele of type S mismatches type T.
How to solve this problem?
Upvotes: 2
Views: 591
Reputation: 39366
Adding a type annotation to widen the type to plain Actor
fixes the problem:
system.actorOf(Props(new Actor{
// ...
}: Actor))
Upvotes: 4
Reputation: 5763
class otherClass[T <: myTrait[T]](){
def func(data: List[T]):List[String]={
val system = ActorSystem()
class FooActor extends Actor {
case object START
case class Job(e1: T, e2: T)
def receive = {
case START =>
context become behavior(data.tail, data.head)
}
def behavior(list: List[T], ele: T):Receive={
case _ =>
sender ! Job(list.head, ele)
context become behavior(list.tail, ele)
}
}
system.actorOf(Props(new FooActor))
List.empty[String]
}
}
Just get ride of that structural
actor creation by wrapping it as a new class
Upvotes: 4
Reputation: 31
Add generic type for behavior method:
def behavior[T](map: HashMap[Int, List[T]], list: List[(T, Int)], ele: T):Receive={
case _ =>
}
https://issues.scala-lang.org/browse/SI-1906 you can't use the abstract type defined outside the structural type due to missing type information at runtime. Check this answer, Using Scala structural types with abstract types.
Upvotes: 1