Как конкретно задать абстрактный тип с привязкой к типу?

Я пытаюсь использовать типы объектов case как абстрактные типы. Я был удивлен, увидев (аналогичный) код ниже компиляции:

sealed abstract class Bar

case object BarOne extends Bar

case object BarTwo extends Bar

sealed abstract class Foo {
  type A <: Bar

  def f: A
}

object Foo {
  object FooOne extends Foo {
    type A = BarOne.type
    val f = BarTwo
  }

  object FooTwo extends Foo {
    type A = BarTwo.type
    val f = BarOne
  }
}

В моем реальном примере Foo параметризируется и используется как класс case. Поэтому я не могу просто сделать A параметр типа.

Как f = BarTwo скомпилировать, когда A установлено как BarOne.type?

Если A в f: A интерпретируется как A <: Bar, почему это так?

Есть ли способ конкретно установить A для каждого экземпляра объекта Foo?


Я использую Scala 2.11.8.


Обновление: при замене val attributeType = ... на def attributeType = ... в FooOne и FooTwo сбой компиляции (как и ожидалось).

Ответ 1

Кто-нибудь предложил вам перейти на современную версию Scala? (Шутка.)

Ошибка об переопределении дает хороший путь для типа.

$ scala
Welcome to Scala 2.12.0-M5 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_92).
Type in expressions for evaluation. Or try :help.

scala> :pa
// Entering paste mode (ctrl-D to finish)

sealed abstract class Bar

case object BarOne extends Bar

case object BarTwo extends Bar

sealed abstract class Foo {
  type A <: Bar

  def f: A
}

object Foo {
  object FooOne extends Foo {
    type A = BarOne.type
    val f = BarTwo
  }

  object FooTwo extends Foo {
    type A = BarTwo.type
    val f = BarOne
  }
}

// Exiting paste mode, now interpreting.

<console>:26: error: overriding method f in class Foo of type => Foo.FooOne.A;
 value f has incompatible type
           val f = BarTwo
               ^
<console>:31: error: overriding method f in class Foo of type => Foo.FooTwo.A;
 value f has incompatible type
           val f = BarOne
               ^

Ошибка была этот, а дублированный вопрос с прошлого ноября.

Характер ошибки был также умен: он был введен -Yoverride-objects, что не очень полезно, но фигурирует в паре моего S.O. ответы, и теперь в вопросе.

Edit:

$ scala
Welcome to Scala 2.11.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_92).
Type in expressions for evaluation. Or try :help.

scala> object X ; object Y
defined object X
defined object Y

scala> class C { def f: X.type = X }
defined class C

scala> class D extends C { override def f: Y.type = Y }
defined class D

scala> :quit
$ scalam
Welcome to Scala 2.12.0-M5 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_92).
Type in expressions for evaluation. Or try :help.

scala> scala> object X ; object Y

// Detected repl transcript. Paste more, or ctrl-D to finish.

defined object X
defined object Y

scala> class C { def f: X.type = X }
defined class C

scala> class D extends C { override def f: Y.type = Y }
defined class D
// Replaying 3 commands from transcript.

scala> object X ; object Y
defined object X
defined object Y

scala> class C { def f: X.type = X }
defined class C

scala> class D extends C { override def f: Y.type = Y }
<console>:13: error: overriding method f in class C of type => X.type;
 method f has incompatible type
       class D extends C { override def f: Y.type = Y }
                                        ^

Ответ 2

Я не знаю, что здесь происходит, но у меня проблема была немного более изолирована. Кроме того, он работает с подклассами Foo, а также с объектами. Я подтвердил этот компилятор на scalac 2.11.8:

object BarOne
object BarTwo

abstract class Foo[A] {
  def attributeType: A
}

object FooContainer {
  class FooOne extends Foo[BarOne.type] {
    val attributeType = BarTwo
  }

  object FooTwo extends Foo[BarOne.type] {
    val attributeType = BarOne
  }
}

Ответ 3

  • A в f: A интерпретируется как A <: Bar
  • Потому что это то, что А представляет, когда F определяется в абстрактном классе
  • Как насчет переопределения абстрактного определения (ниже не будет компилироваться):

    object Foo {
    
      object FooOne extends Foo {
        type A = BarOne.type
        override val f: A = BarTwo
      }
    
      object FooTwo extends Foo {
        type A = BarTwo.type
        override val f: A = BarOne
      }
    
    }