Having created a new type by mixing in a ObservableSet
with a HashSet
, I was kind of expecting to replace then be able to use the new type to create a new instance as in "foo" below. But this does not compile, although using the original long form of the type seems fine (as shown in "bar", below).
Is this just a feature of the language or have I done something daft?
package whatever
import collection.mutable._
object Whatever {
type ObservableHashSet[T] = HashSet[T] with ObservableSet[T]
class X
def foo {
new ObservableHashSet[X]
}
def bar {
new HashSet[X] with ObservableSet[X]
}
}
The error is ..
error: class type required but scala.collection.mutable.HashSet[scala.Whatever.X] with scala.collection.mutable.ObservableSet[scala.Whatever.X] found
new ObservableHashSet[X]
The brief version is that you've created a type alias for a structural type (that you can not instantiate).
This is a simplified version of what you've done (does not work):
scala> import collection.mutable._
import collection.mutable._
scala> type ObservableHashSet[T] = HashSet[T] with ObservableSet[T]
defined type alias ObservableHashSet
scala> new ObservableHashSet[String]
<console>:12: error: class type required but scala.collection.mutable.HashSet[String] with scala.collection.mutable.ObservableSet[String] found new ObservableHashSet[String]
Now, the error does make some sense, and let me try to explain why.
With type ObservableHashSet[T] = HashSet[T] with ObservableSet[T]
you're defining a type alias for something that is not a concrete type (or, as the error message says, not a "class type"), so you can't create an instance of it with new
.
But this (with an intermediate step where we do create a class type) works:
scala> class ObservableHashSet[T] extends HashSet[T] with ObservableSet[T]
defined class ObservableHashSet
scala> type obs[T] = ObservableHashSet[T]
defined type alias obs
scala> new obs[String]
res1: ObservableHashSet[String] = Set()
So, the question is: why does scala let you create a type alias that you can't instantiate?
Well, type ObservableHashSet[T] = HashSet[T] with ObservableSet[T]
is a structural type. Although, as you've seen in the first snippet of code, you can't create an instance of it, you can still use it: e.g. to put a structural constraint on an argument of a function.
Take a look:
scala> type ObservableHashSet[T] = HashSet[T] with ObservableSet[T]
defined type alias ObservableHashSet
scala> def test(obsHashSet: ObservableHashSet[String]) : String = {"bingo!"}
test: (obsHashSet: ObservableHashSet[String])String
scala> test(new HashSet[String] with ObservableSet[String])
res4: String = bingo!
but if we try to call test with an argument that does not conform to the structural type we get a type mismatch:
scala> test(new HashSet[String])
<console>:13: error: type mismatch;
found : scala.collection.mutable.HashSet[String]
required: ObservableHashSet[String]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With