1

While working in a sparkSql UDAF function I find some of my input columns turns from null to 0 unexpectedly.

With some REPL practice, it turns out the behavior is of scala 2.10.5.

code snap as bellow

import scala.collection.mutable

val wa = mutable.WrappedArray.make[Int](Array(null, null))

wa

wa(1)

Would you please someone family with scala help explain why and what is happening behind the hood?

Kai
  • 33
  • 7

1 Answers1

1

You called method make[Int] which is declared as follows:

def make[T](x: AnyRef): WrappedArray[T] = (x match {
    case null              => null
    case x: Array[AnyRef]  => new ofRef[AnyRef](x)
    case x: Array[Int]     => new ofInt(x)
    case x: Array[Double]  => new ofDouble(x)
    case x: Array[Long]    => new ofLong(x)
    case x: Array[Float]   => new ofFloat(x)
    case x: Array[Char]    => new ofChar(x)
    case x: Array[Byte]    => new ofByte(x)
    case x: Array[Short]   => new ofShort(x)
    case x: Array[Boolean] => new ofBoolean(x)
    case x: Array[Unit]    => new ofUnit(x)
  }).asInstanceOf[WrappedArray[T]]

In your case x is Array(null, null) which is instance of Array[AnyRef], so make creates and returns instance of class ofRef[AnyRef] which is declared as:

final class ofRef[T <: AnyRef](val array: Array[T]) extends WrappedArray[T] with Serializable {
  lazy val elemTag = ClassTag[T](arrayElementClass(array.getClass))
  def length: Int = array.length
  def apply(index: Int): T = array(index).asInstanceOf[T]
  def update(index: Int, elem: T) { array(index) = elem }
}

When you call wa(1), you call method apply of this class and since your second element is null it will return 0, because null.asInstanceOf[Int] returns 0.

Duelist
  • 1,562
  • 1
  • 9
  • 24
  • "`null.asInstanceOf[Int]` returns `0`" is the punch line (and is rather surprising) – Tzach Zohar Jun 12 '18 at 18:28
  • Thank you very much @Duelist. – Kai Jun 12 '18 at 18:38
  • And I've just find out another odd behavior that if I write following pattern match function, I will get the **null** back again. val f = (x:Any) => { x match { case i: Int => "integer" case null => "Null"}} f(wa(1)) f(1) f(null) So, it also have something todo with lazy evaluation, right? – Kai Jun 12 '18 at 18:47
  • 1
    Could you clarify please? I see nothing wrong in your function expect you should add case with underscore to handle other parameters. – Duelist Jun 12 '18 at 18:59
  • Sorry, forget about it. the null.asInstanceOf[Int] do not happen if I just do a evaluation of `val f = (x:Any) => { x match { case i: Int => "integer" case null => "Null"}} f(wa(1)) f(1) f(null)` in scala shell. As the result is printed as "Null". – Kai Jun 21 '18 at 04:13
  • That's ok, there is no class casting using `asInstanceOf` in pattern matching, it only checks the type `null.isInstanceOf[Int]` which return `false`. Even more it returns `false` when we check `null.isInstanceOf[AnyRef]` or even `null.isInstanceOf[Any]`. So you only can match `null` as `case null => ...` or `case _ => ...` – Duelist Jun 21 '18 at 06:30