tags:

views:

183

answers:

1

I have a class that inherits the Actor trait. In my code, I have a method that creates x numbers of this actor using a loop and another method that simply sends the Finish message to all of them to tell them to terminate. I made the kill method just take an array of Actor since I want to be able to use it with an array of any type of Actor. For some reason, however, when I pass a value of type Array[Producer], where Producer extends Actor, to a method that accepts the type Array[Actor], I get a type error. Shouldn't Scala see that Producer is a type of Actor and automatically cast this?

+6  A: 

What you are describing is called covariance, and it is a property of most of the collection classes in Scala--a collection of a subtype is a subtype of the collection of the supertype. However, since Array is a Java primitive array, it is not covariant--a collection of a subtype is simply different. (The situation is more complicated in 2.7 where it's almost a Java primitive array; in 2.8 Array is just a plain Java primitive array, since the 2.7 complications turned out to have unfortunate corner cases.)

If you try the same thing with an ArrayBuffer (from collection.mutable <- edit: this part is wrong, see comments) or a List (<- edit: this is true) or a Set (<- edit: no, Set is also invariant), you'll get the behavior you want. You could also create an Array[Actor] to begin with but always feed it Producer values.

If for some reason you really must use Array[Producer], you can still cast it using .asInstanceOf[Array[Actor]]. But I suggest using something other than primitive arrays--anything you could possibly be doing with actors will be far slower than the tiny overhead of using a more full-featured collection class.

Rex Kerr
I just changed my Array's to mutable.ArrayBuffer's, but am still getting the same casting issue. BTW, I'm using Scala 2.7.7.
Chris Lieb
However, switching the collection objects to contain Actor instead of my subclasses seems to have fixed things up.
Chris Lieb
Whoops--I forgot that a lot of the `mutable` collection is invariant. `immutable.Vector` would work, though.
Rex Kerr
I should add that with the mutable collections, the invariance is there for good reason. Suppose you have an `Array[Producer]`, pass it to a function that takes an `Array[Actor]`, that function puts some actors in it that are _not_ `Producers`, and then you use your array again. You think it's all `Producers`, but it's not! If the thing was immutable, that last step (they change it and you don't realize) is impossible, so it's not a concern, so the collection can be covariant. But with mutable collections, it's your job to make it broad enough to start (e.g. as `Array[Actor]`).
Rex Kerr