Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating an instance of a type alias causes "class type required" error

Tags:

scala

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]
like image 585
Richard Avatar asked Nov 07 '11 18:11

Richard


1 Answers

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]
like image 69
Paolo Falabella Avatar answered Nov 17 '22 19:11

Paolo Falabella