7

I see in the built-in class MessageQueue.scala of scala 2.7.7, around line 164, it's:

def extractFirst(p: Any => Boolean): MessageQueueElement = {
changeSize(-1) // assume size decreases by 1

val msg = if (null eq last) null
else {
    ...
  }
}

I don't understand val msg = if (null eq last) null well, why it uses eq, but not null. If I write if (last==null) null, is it correct? Is there any difference?

Freewind
  • 193,756
  • 157
  • 432
  • 708

2 Answers2

14

When either side of the == is null or if the first operand of == evaluates to null, then Scala will not invoke equals. So, in this case, yes, x == null is the same as x eq null; the equals method is not invoked. Pay attention to the cases below.

Consider this:

class X {
   // this is just for testing
   // any equals that returns true when the other object is null
   // is arguably broken. thus even though it may be invoked
   // the end semantics should remain the same
   override def equals(x: Any) = true
}
var x = new X()
x == null // false -- compiler optimization?
null == x // false
var y = null
y == x // false -- see documentation below, y is null, x is not
x == y // true  -- x does not evaluate to null, equals invokes
x eq y // false

And note that:

(new X()) == null

Results in a warning saying a "a fresh object" will never be equal (to null).

I suspect there may be slightly more/different code emitted for x == y than x == null (in case the equals must be invoked), but have not checked.

Happy coding.


Section 6.3 (The Null Value) of the Scala Language Specification has this to say:

The null value is of type scala.Null, and is thus compatible with every reference type. It denotes a reference value which refers to a special “null” object. This object implements methods in class scala.AnyRef as follows:

  • [null] eq( x ) and [null] ==( x ) return true iff the argument x is also the “null” object.
  • ne( x ) and !=( x ) return true iff the argument x is not also the “null” object.
  • isInstanceOf[T ] always returns false.
  • asInstanceOf[T ] returns the “null” object itself if T conforms to scala.AnyRef, and throws a NullPointerException otherwise.

A reference to any other member of the “null” object causes a NullPointerException to be thrown.

  • thank you. So, `val msg = if (null eq last) null` can be replaced with `val msg = if(null==last) null`, but not `val msg = if(last==null) null`, right? – Freewind Aug 14 '11 at 06:38
  • @Freewind My testing indicates that `x == null` and `null == x` are both treated as `x eq null` and `null eq x`, respectively. (I believe as a compiler optimization). The only case that seems "out" is `x == y`, where x *does not* evaluate to null -- in that case (and only that case) the equals method is invoked. However, even if equals is *not invoked* when `x` evaluates to null in `x == y`, the compiler may not be able to generate as efficient bytecode as when `null` appears as one of the operands because it doesn't know that `x` will evaluate to null. –  Aug 14 '11 at 06:40
  • Thank you again! So, I can write both `val msg=if(null==last)null` and `val msg = if(last==null) null` for that line of code. – Freewind Aug 14 '11 at 10:19
0

The operator == in scala is different from Java's.

In scala, == is equivant to equals method in Any, eq is equivant to == in Java

BTW, why doesn't null.asInstanceOf[Int], null.asInstanceOf[Double], null.asInstanceOf[Boolean], null.asInstanceOf[Char] throw NullPointerException ?

爱国者
  • 4,298
  • 9
  • 47
  • 66
  • "Approximately equivalent". See the cases in my answer that show the mapping isn't entirely 1-1. Consider posting a *new* question wrt. `asInstanceOf`. Since `Int` "does not conform to" `AnyRef`, I am not sure why it doesn't throw a NPE. –  Aug 14 '11 at 16:42
  • I have post a question http://stackoverflow.com/questions/8285916/why-doesnt-null-asinstanceofint-throw-a-nullpointerexception – 爱国者 Nov 27 '11 at 13:44