宇宙人
宇宙人

Reputation: 1227

scala, parameter type in structural refinement

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

Answers (3)

Owen
Owen

Reputation: 39366

Adding a type annotation to widen the type to plain Actor fixes the problem:

system.actorOf(Props(new Actor{
    // ...
}: Actor))

Upvotes: 4

jilen
jilen

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

user3931649
user3931649

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

Related Questions