11
def test1(a: Any) = a match { case x: AnyRef => "AnyRef" case _ => "None of the above" } def test2(a: Any) = a match { case x: Double if x > 2 => "Double > 2" case x: AnyRef => "AnyRef" case _ => "None of the above" } 

Please can someone explain why in the following, the first case 1.0 matches on AnyRef, but in the second it doesn't. (Scala 2.9.0-1)

scala> test1(1.0) res28: java.lang.String = AnyRef scala> test2(1.0) res29: java.lang.String = None of the above 

edit - Scala 2.10 update Jan 2013: the new pattern matcher fixes this behaviour (or at least, makes it consistent) and the method test2 now returns "AnyRef" as for test1.

4
  • 2
    when compiled, what's generated is if(a instanceof Double) { if(a > 2) { return "Double > 2"} else { return "None of the Above" } } else { if(a instanceof Object) { return "AnyRef"} else {return "None of the Above"}} . So, unless someone find something in the scala specification, I think it's scala compiler bug Commented Nov 10, 2011 at 20:00
  • 1.0 is a Double which is a subtype of Any but not of AnyRef in contrast to java.lang.Double. So I even wonder why 1.0 matches AnyRef in test1. Commented Nov 10, 2011 at 20:05
  • 1
    I deleted my answer. It is not a bug -- I did not notice you were matching against AnyRef. Rex Kerr is correct. Commented Nov 10, 2011 at 22:12
  • @PeterSchmitz: according to the spec, you're right. Commented Feb 10, 2012 at 0:40

1 Answer 1

6

This is because Any is actually just an Object. Having Double there is a convenient fiction--it's actually java.lang.Double which is autounboxed for you in the match statement. Unfortunately, there is no way for Scala to tell if it finds a java.lang.Double if it is supposed to be interpreted as a Double or as a java.lang.Double--in the latter case, the AnyRef should catch it. So it does. But if you specifically ask for a Double, it knows it is supposed to unbox, and then the AnyRef case need not be checked. (And, in fact, if you intended it to be a java.lang.Double, it will unbox that too--it can't tell the difference.)

Whether this is ideal behavior is debatable, but it is logical.

Sign up to request clarification or add additional context in comments.

6 Comments

Thanks, now I understand why 1.0 is matched in test1.
@RexKerr I am not sure I still buy it. "in the latter case, the AnyRef should catch it." except that it doesn't since "None of the Above" is printed. I also assume that a match case's result should equal it's composing partial functions... val x:PartialFunction[Any, String] = {case x:Double if x > 2 => "Double > 2"} val y:PartialFunction[Any, String] = {case x:AnyRef => "AnyRef"} val z:PartialFunction[Any, String] = {case _ => "None of the Above"} println(test2(1.0)) // => None of the Above val chain = x orElse y orElse z println(chain(1.0)) // => AnyRef
@DanielHinojosa - As I said, I'm not sure that this is ideal: AnyRef should catch it unless you specify you want Double. One could argue that the guard on Double should indicate that you only want those Doubles to be considered as not-AnyRef, and the rest should be caught by AnyRef as normal.
Is this behavior described in the Scala specification? I really wonder how the present behavior can be formalized in general.
@RexKerr: Well, it won't generalize beyond AnyVal children, nor beyond permutations of the different cases. Anyway, I did look up in the spec, and neither Sec. 12.2, nor Sec. 8.1-8.2 hint at any such problem, so the first code fragment does not agree with the specification. But I fear the day when matching against AnyRef will work and filter out matches against AnyVal, given the performance cost. I think matches against AnyRef should trigger a warning or an error, suggesting to match against Any, especially since AnyVal is already forbidden.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.