Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type pattern match why a variable is a must

I am reading "Scala for Impatient 2nd" Section 14.4, where I am confused about the context :

You can match on the type of an expression, for example :

obj match {
   case x:Int => x
   case s:String => Integer.parseInt(s)
   case _:BigInt => Int.MaxValue
   case _ => 0
}

When you match against a type, you must supply a variable name. Otherwise, you match the object :

obj match {
   case _:BigInt => Int.MaxValue // Matches any object of type BigInt
   case BigInt => -1 // Matches the BigInt object of type Class
}

What I am confused is how to understand obj which is requested as an expression : if I test as below :

val x = 121
val obj : Any = x
obj == 121 // true

obj match {
   case x:Int => x
   case s:String => Integer.parseInt(s)
   case _:BigInt => Int.MaxValue
   case _ => 0
} // res133: Int = 121

However if I just assign an Integer value to obj, compiler throws error :

val obj2 = 121
obj2 == 121 // true

obj2 match {
   case x:Int => x
   case s:String => Integer.parseInt(s)
   case _:BigInt => Int.MaxValue
   case _ => 0
} // <console>:22: error : scrutinee is incompatible with pattern type;
found : String
required : Int
    case s : String => Integer.parseInt(s)
             ^    
<console>:23: error : scrutinee is incompatible with pattern type;
found : BigInt
required : Int
    case _ : BigInt => Int.MaxValue
             ^      

The only difference is the former example I assigned obj by another variable, while the latter example I assigned obj by a Integer value. Why there is a compile error for latter example ?

Question update : I understand that "compiler knows that obj2 is Int", however, I thought that was what match expression works for, i,e because obj2 is Int and it met the first match clause case x:Int => x thus match is successful and the whole match expression completed. I thought this should be exactly the same as former example, the only difference is that the two variables are of Any and of Int type, but they all matched the first match clause and both of them should be compiled properly.

From this book Section 14.4 "In Scala, this (type pattern) match is preferred to using the isInstanceOf operator", I thought using type patterns is a way to identify object's type. If we have known the object type, what is "type pattern" used for ?

The second question is I am confused the context below. How to understand "object of type BigInt" v.s "BigInt object of type Class" ? is "type Class" related to java generic/reflection concept ?

obj match {
   case _:BigInt => Int.MaxValue // Matches any object of type BigInt
   case BigInt => -1 // Matches the BigInt object of type Class
}

Thank you !

like image 515
Jacqueline P. Avatar asked Apr 19 '26 17:04

Jacqueline P.


1 Answers

In the second case, the compiler knows that obj2 is Int and therefore it knows that it is impossible that a match for String or BigInt could succeed.


There is a distinction here between what is known at compile time and what is known at run time. You have the following code:

val x = 121
val obj: Any = x

At run time, both x and obj are Int and will match the first case in your match expression.

At compile time the compiler knows that x is Int so it knows that there is no point in testing for String or BigInt. All it knows about obj is that it is Any so it is OK to check for String, BigInt or any other type.

Now in this case it is clear that the compiler could work out that obj is actually Int, but this is not possible in the general case. Rather than having complex rules about type inference, the compiler just uses the type that the programmer gave to the value which is Any. So it assumes that obj could be String or BigInt even though in this case it is obvious from the code that it isn't.

like image 184
Tim Avatar answered Apr 23 '26 13:04

Tim



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!