views:

203

answers:

4

I don't understand why the following case doesn't match. Null should be an instance of Any, but it doesn't match. Can someone explain what is going on?

val x = (2, null)
x match {
    case (i:Int, v:Any) => println("got tuple %s: %s".format(i, v))
    case _ => println("catch all")
}

prints catch all

Thanks.

+1  A: 

I'm just guessing here since I'm no scala expert but according to the documentation for the Any class in scala I'm thinking that since null isn't an object, it doesn't derive from Any and as such doesn't match the first listed case.

Adding the code sample below. It prints "something else" when run.

val x = (2, null)  
x match {  
    case (i:Int, v:Any) => println("got tuple %s: %s".format(i, v))  
    case (i:Int, null) => println("something else %s".format(i))
    case _ => println("catch all")  
}  

After more research it seems like null should match with any sense the documentation says that it extends AnyRef which extends Any.

EDIT: Like everyone else has said. The first case doesn't match null on purpose. It's specified in the documentation.

Brian Hasden
`null` is the singleton instance of the class `Null`.
Daniel
That makes sense. The documentation for null (http://www.scala-lang.org/docu/files/api/scala/Null.html) says it extends AnyRef which extends Any, so it seems like it should match case(i:Int, v:Any).
Brian Hasden
+8  A: 

This is exactly as specified.

Type patterns consist of types, type variables, and wildcards.
A type pattern T is of one of the following forms:

* A reference to a class C, p.C, or T#C.
This type pattern matches any non-null instance of the given class.

It's interesting that so much relevance has been attributed to null being a member of Any. It's a member of every type but AnyVal and Nothing.

extempore
I presume a/the motivation for this choice is that it matches the behaviour of the "instanceof" bytecode on the JVM.
Matt R
That, and letting null through would completely suck. You must have an obscene null tolerance to go looking for motivations!
extempore
"Obscene null tolerance" or not, there's an argument that the most natural and straightforward meaning for a type pattern "x: T" is to match any member of type T. For example, it would avoid irregularities like "val x: Any = null" -- fine, but "val (x: Any, y: Any) = (null, null)" -- MatchError. That "completely sucks" too.I'm not saying that Scala made the wrong choice, nor that it's particularly important given that idiomatic Scala avoids using null.
Matt R
That's a poor example since that issue has nothing to do with null. "val (x: Int, y: Long) = (5, 5)" also fails with a match error. In any case, if you're using null in such a way that this comes up, I propose that you're doing it wrong.
extempore
I'm afraid I don't follow you. Your example fails, I presume, because the second 5 is type inferred as an Int, so it fails the runtime type test, but that doesn't seem applicable to my example.
Matt R
+1  A: 

That's as specified (Scala Reference 2.7, section 8.2):

A reference to a class C, p.C, or T#C. This type patternmatches any non-null instance of the given class. Note that the prefix of the class, if it is given, is relevant for determining class instances. For instance, the pattern p.C matches only instances of classes C which were created with the path p as prefix.

Daniel
+2  A: 

Have you tried the v placeholder for anything?

val x = (2, null)
x match {
    case (i:Int, v) => println("got tuple %s: %s".format(i, v))
    case _ => println("catch all")
}
oxbow_lakes