По имени скала самоподобного типа еще тени "это"? - PullRequest
3 голосов
/ 20 января 2011

Работа с этими сообщениями заставила меня подумать, что я, по крайней мере, немного понимаю самоподтипы.

Поэтому я создал пример, который не удался, как и ожидалось:*

scala> trait A { val v = "a" }
defined trait A

scala> trait B { this :A => ; var v = "" ; this.v = "b" }
<console>:6: error: reassignment to val
       trait B { this :A => ; var v = "" ; this.v = "b" }
                                                  ^

Самоподобное «это» затмевает «это» В - это выглядит странно, но имеет смысл.

Казалось бы, разумно дать самому типу другое имя.Я сделал это и был довольно удивлен:

scala> trait C { a :A => ; var v = "" ; this.v = "c" }
<console>:6: error: reassignment to val
       trait C { a :A => ; var v = "" ; this.v = "c" }
                                               ^

Это все еще затенено ???

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

scala> trait D { a :A => ; var w = "" ; this.w = a.v }
defined trait D

(И имя собственного типа можно при желании использовать, чтобы уточнить, какой «v» использовать.)

Хорошо.Что означает, что следующее должно потерпеть неудачу?

scala> trait E { this :A => ; var w = "" ; this.w = this.v }
defined trait E

А?Что это такое?: - (

Итак ... есть ли смысл называть себя типами? "Это", кажется, в конечном итоге затенено независимо.

Или это крайний случай правил области видимости,где тип «это» самоподобного типа имеет приоритет над «этим» черты - и нужно просто избегать использования одних и тех же имен для вещей в связанных чертах?

Ответы [ 2 ]

8 голосов
/ 20 января 2011

Ваша проблема не в имени типа self (во всех ваших примерах и this, и альтернативное имя типа self относятся к одной и той же вещи и имеют один и тот же тип, а именно 'наибольшая нижняя граница B и A '[§5.1, Спецификация языка Scala]), но вы пытаетесь определить поле с тем же именем снова без явного переопределения.

Посмотрите на более простой пример:

trait A { val v = "a" }
trait B { this: A =>
  var v = "b"
}

new A with B {} // does not compile

<console>:9: error: overriding value v in trait A$class of type java.lang.String;
 variable v in trait B$class of type java.lang.String needs `override' modifier
   new A with B {}

Итак, даже если вы не получили ошибку при определении B, вы все равно просто не можете ее использовать.

Это сработает

trait A { val v = "a" }
trait B { this:A => override val v = "b"  }

new A with B {}

Здесь вы явно переопределяете A v в B.(Обратите внимание, что new B with A {} потерпит неудачу, потому что B должен стоять последним.) Кроме того, это должен быть val, потому что в большинстве случаев вы не можете переопределить var s, и вы не можете переопределить что-то еще, используя var.

Как правило, в этих простых случаях вам не нужно беспокоиться о названии типа.Пока вы не создадите другую черту или класс внутри B, и this, и все, что вы бы назвали своей переменной собственного типа, будут указывать на одно и то же.Там не будет затенения.Если у вас есть новая черта внутри B, и вам нужно сослаться на экземпляр B внутри этой черты, вам потребуется другое имя для вашего собственного типа.

Учтите это

trait B { this =>
  val v = "b"
  trait C {
    val v = "c"
    println(this.v)
  }
  new C {}
}
new B {}

// prints c

против этого:

trait B { self =>
  val v = "b"
  trait C {
    val v = "c"
    println(this.v)  // prints c
    println(self.v)  // prints b
  }
  new C {}
}
new B {}

(Без каких-либо дальнейших аннотаций типов вы можете опустить все this в этом примере.)

4 голосов
/ 20 января 2011

Тип личности не следит за этим. Это тип этого. (На самом деле self-тип - это пересечение: в черте A {self: B => ...} типом этого является A с B.) Вы можете указать имя, задавая self-тип для удобства устранения неоднозначностей. , но поскольку у вас никогда не было более одного этого кода в любом из ваших фрагментов кода, это не имеет значения.

[...] где тип «это» имеет приоритет над признаком «это»

У вас есть одна и та же идея в нескольких местах, что существует более одного этого. Нет Есть только это. Вы не получите еще один, пока не объявите другой шаблон.

trait A {
  self1 =>

  trait B {
    self2 =>

    // Here unqualified this refers to B and not A, so "self1" is useful.
    // ...but not necessary, because A.this.xxx does the same thing.
  }
}
...