
Type inference
We can call type inference a built-in Scala feature that permits us to omit type information while writing code. This means we don't have to specify the type while declaring any variables; Scala compiler can do it for us:
scala> val treatMeAString = "Invisible"
treatMeAString: String = Invisible
We did not specify our val, to be of String type, but seeing the value of Invisible, Scala compiler was able to infer its type. Also with some constraints, we can also omit the method's return types:
defcheckMeImaString(x: Boolean) = if(x) "True"else "False"
Here we did not give the return type, as Scala compiler was able to infer its type. But for recursive methods, this doesn't work. The famous factorial method expects you to specify the return type if implementation is recursive:
def recursiveFactorial(n: Int) = if(n == 0) 1 else recursiveFactorial(n-1)
//Recursive method recursiveFactorial needs result type
Scala uses a constraints-driven algorithm to implement type inference. It means that Scala compiler tries to infer constraints, and then attempts to unify the type. We're talking about constraints, but what are they? A constraint is a statement about the types of expression. And even if it's not an expression, for example, when we bind a value to a variable, we must deduce their type too. But first think about what we can deduce from the type of an expression:
- If it is related to the type of some identifier
- If it is related to the type of some other expression
- If it is a base type, such as numbers and Booleans
- If it is a constructed type such as a function, whose domain and range types are further constrained
Scala compiler uses this approach to deduce constraints and then apply unification (explanation is beyond the scope of this book) to infer the type. In instances where we can't take out any statements about an expression, inferring type is impossible:
scala> val x = x => x
<console>:11: error: missing parameter type
val x = x => x
Because of type inference only, we're able to use syntactic sugar for cases where we're not expected to specify types:
scala> List(1,4,6,7,9).filter(_+1 > 5)
res0: List[Int] = List(6, 7, 9)
Exciting, isn't it? This way, we've performed our logic simply with less information about types. The underscore (_) used is syntactic sugar, and it's possible to use here because of type inference.
We'll continue our good work and learn about implementing this, perform operations using all these types, and strengthen our basics.