Неожиданное поведение значений по умолчанию в Scala - PullRequest
3 голосов
/ 05 декабря 2009

Почему значения по умолчанию здесь ведут себя по-разному при явном присвоении значению val по сравнению с напечатанным напрямую?

package blevins.example

class SimpleWrap[T] {
  var t: T = _
  def get = t
}

object App extends Application {
  val swb = new SimpleWrap[Boolean]
  val b = swb.get
  println("b: " + b)  // b: false
  println("swb.get: " + swb.get) // swb.get: null

  val swi = new SimpleWrap[Int]
  val i = swi.get
  println("i: " + i) // i: 0
  println("swi.get: " + swi.get) // swi.get: null
}

Я использую 2.8r19890.


Edit - Кажется, странность происходит, когда "get" вызывается в ожидании Any.

  val any1: Any = swb.get
  val any2: Any = b
  println("any1: " + any1) // any1: null
  println("any2: " + any2) // any2: false

1 Ответ

4 голосов
/ 06 декабря 2009

Я почти уверен, что это как-то связано с упаковкой / распаковкой примитивов. Если вы пишете универсальный код для работы с примитивами, вы должны поместить примитив в коробку, а затем распаковать его в том месте, где вы использовали его в качестве примитива. Я не уверен, какой алгоритм распаковки используется, но я предполагаю, что он имеет следующие черты:

if(box == null) 
  default value
else
  box.unbox

Следовательно, очень странно, я мог бы добавить, что значение по умолчанию для поля t в вашем классе простой оболочки всегда будет null, так как поле всегда будет в штучной упаковке примитивный, так как генерики реализованы на уровне JVM по типу стирания. Поэтому все, что видит JVM, это то, что t имеет тип Object со значением null. Поэтому метод get всегда будет возвращать null, но когда универсальный метод get должен возвращать примитивный тип, null распаковывается со значением по умолчанию.

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

val sw = new SimpleWrap[Boolean]
sw.getClass.getDeclaredFields.map {
  f => f.setAccessible(true)
  f.get(sw) 
  }

О, удовольствие null с. Одним из решений этой проблемы было бы использование аннотации 2.8 @specialised, если это было реализовано в используемой вами ночной сборке.

Или, что еще лучше, компилятор Scala может использовать в этих полях значения по умолчанию для коробок по умолчанию с действительными значениями по умолчанию используемых примитивов. Например, в случае SimpleWrap[Boolean], t будет иметь тип Object и значение java.lang.Boolean(false) во время выполнения.

РЕДАКТИРОВАТЬ: Отчет об ошибке отправлено .

Еще одна странная вещь:

val x: Int = null.asInstanceOf[Int] // 0
val y: Boolean = null.asInstanceOf[Boolean] // false

Это то, что нужно решить, чтобы дженерики действительно были родовыми и имели согласованное поведение! На данный момент ваш метод get не имеет согласованного поведения.

- Flaviu Cipcigan

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...