Given:
case object A
What's the difference, if any, between the @
and :
in:
def f(a: A.type): Int = a match {
case aaa @ A => 42
}
and
def f(a: A.type): Int = a match {
case aaa : A.type => 42
}
The first one @
uses an extractor to do the pattern matching while the second one :
requires the type - that's why you need to pass in A.type
there.
There's actually no difference between them in terms of matching. To better illustrate the difference between @
and :
we can look at a simple class, which doesn't provide an extractor out of the box.
class A
def f(a: A) = a match {
case _ : A => // works fine
case _ @ A => // doesn't compile because no extractor is found
}
In this very specific case, almost nothing is different. They will both achieve the same results.
Semantically, case aaa @ A => 42
is usage of pattern binding where we're matching on the exact object A
, and case aaa : A.type => 42
is a type pattern where we want a
to have the type A.type
. In short, type versus equality, which doesn't make a difference for a singleton.
The generated code is actually slightly different. Consider this code compiled with -Xprint:patmat
:
def f(a: A.type): Int = a match {
case aaa @ A => 42
case aaa : A.type => 42
}
The relevant code for f
shows that the two cases are slightly different, but will not produce different results:
def f(a: A.type): Int = {
case <synthetic> val x1: A.type = a;
case6(){
if (A.==(x1)) // case aaa @ A
matchEnd5(42)
else
case7()
};
case7(){
if (x1.ne(null)) // case aaa: A.type
matchEnd5(42)
else
case8()
};
case8(){
matchEnd5(throw new MatchError(x1))
};
matchEnd5(x: Int){
x
}
}
The first case checks equality, where the second case only checks that the reference is not null
(we already know the type matches since the method parameter is the singleton type).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With