Создание экземпляра псевдонима типа приводит к ошибке типа "тип класса"

Создав новый тип путем смешивания в ObservableSet с HashSet, я как бы ожидал замены, а затем смог использовать новый тип для создания нового экземпляра, как показано ниже в "foo". Но это не скомпилируется, хотя использование оригинальной длинной формы типа кажется прекрасным (как показано в "bar", ниже).

Это просто особенность языка или я сделал что-то глупое?

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]
  }
}

Ошибка:

error: class type required but scala.collection.mutable.HashSet[scala.Whatever.X] with scala.collection.mutable.ObservableSet[scala.Whatever.X] found
new  ObservableHashSet[X]

Ответ 1

Краткая версия состоит в том, что вы создали псевдоним типа для структурного типа (который вы не можете создать).

Это упрощенная версия того, что вы сделали (не работает):

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]

Теперь ошибка имеет смысл, и позвольте мне попытаться объяснить, почему.

С помощью type ObservableHashSet[T] = HashSet[T] with ObservableSet[T] вы определяете псевдоним типа для того, что не является конкретным типом (или, как сказано в сообщении об ошибке, а не "тип класса" ), поэтому вы не можете создать экземпляр его с помощью new.

Но это (с промежуточным шагом, на котором мы создаем тип класса) работает:

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()

Итак, возникает вопрос: почему scala позволяет создать псевдоним типа, который вы не можете создать? Хорошо, type ObservableHashSet[T] = HashSet[T] with ObservableSet[T] является структурным типом. Хотя, как вы видели в первом фрагменте кода, вы не можете создать его экземпляр, вы все равно можете его использовать: например. поставить структурное ограничение на аргумент функции.

Посмотрите:

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!

но если мы попытаемся вызвать тест с аргументом, который не соответствует структурному типу, мы получим несоответствие типа:

scala> test(new HashSet[String])
<console>:13: error: type mismatch;
 found   : scala.collection.mutable.HashSet[String]
 required: ObservableHashSet[String]