Странное поведение приведения (.asInstanceOf [T]) в Scala 2.9 - PullRequest
0 голосов
/ 19 декабря 2011

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

Прямо сейчас я испытываю странное поведение в моей карте-функции.Функция карты принимает в качестве входных данных объект-функцию, который может выводить тип, отличный от входного аргумента.

Взгляните на следующий код:

class SeqMPJ[T](indexedSeq: IndexedSeq[T]) {

  val seq = indexedSeq.view //Lazy
  val freeRanks = MPJEnv.getFreeRanks(seq.size)
  //Get n free ranks
  val commGroup = MPI.COMM_WORLD.group.Incl(freeRanks.toArray)
  //Communicator for this sequence
  val comm = MPI.COMM_WORLD.Create(commGroup)

  val opIndex = globalRank % seq.size
  var operand: Any = seq(opIndex)

  if (!isOnline)
    error("Cannot use MPJ-abstractions outside parallelize body...")

  //Only works for p=n now
  def mapMPJ[U](f: (T) => U): SeqMPJView[U] = {
    if (freeRanks.contains(globalRank)) { //Process is part of this operation
      operand = f(operand.asInstanceOf[T])
    }
    return new SeqMPJView(operand.asInstanceOf[U], comm, freeRanks)
  }

...

Обратите внимание, что в функции mapMPJ[U](f: (T) => U):SeqMPJView[U] функция f имеет тип ввода T и тип вывода U. Это означает, что после применения f к переменной «операнд» операнд имеет тип U, однако это происходит внутриесли-блок.Другими словами, в зависимости от состояния, операнд имеет тип U или T. Теперь, когда я приводил к U, это всегда успешно.Даже когда условие в блоке if не выполняется.Насколько я понимаю, программа должна завершиться с ошибкой при приведении operand.asInstanceOf [U], если программа не входит в блок if.

Пример использования в этом умножении матрицы:

val M = 2
val N = 2

val A = Array(
  Array(1.0, 2.0),
  Array(3.0, 4.0))

val B = Array(
  Array(1.0, 2.0),
  Array(3.0, 4.0))

val Bt = B.transpose

/*
 * DNS using underlying MPI
 */
parallelize(args) {

  for (i <- 0 until M; j <- 0 until N)
    A(i) zip Bt(j) mapMPJ { case (a, b) => a * b } reduceMPJ (_ + _)

  if (globalRank == 0)
    println("CHECK RESULT:\n" + Matrix(A) * Matrix(B))

}

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

edit

Естьнеявное преобразование из Array в seqMPJ, FYI.

1 Ответ

4 голосов
/ 19 декабря 2011

Приведение - это только то, что вы утверждаете компилятору, что вы знаете, что делаете, и что такое тип на самом деле, когда дело доходит до аргументов универсального типа. Все они на самом деле просто AnyRef == java.lang.Object (или каков бы ни был ограничивающий тип). Если вы врете этому, он вам поверит (до тех пор, пока не возникнет исключение времени выполнения, вызванное неправильным типом где-то используемого типа). Если вы хотите узнать, есть ли у вас правильный тип, вы должны проверить с помощью манифестов.

Вот пример:

def example[A: ClassManifest,B: ClassManifest](a: A) = {
  if (implicitly[ClassManifest[A]] <:< implicitly[ClassManifest[B]]) a.asInstanceOf[B]
  else throw new Exception("Wrong!")
}

Если вы попробуете бросок, который не сработает, вы будете кричать:

scala> example[List[Int],List[String]](List())
java.lang.Exception: Wrong!

Вы можете соответствующим образом изменить свой код, например,

implicitly[ClassManifest[U]].erasure.isAssignableFrom(operand.getClass)
...