Type inference

The preceding type hierarchy is quite important for understanding how type inference works. Type inference is a mechanism that the compiler uses to guess the type of an expression or a method if the definition of its type is omitted. The same also applies to the type parameters of polymorphic methods or generic classes and sometimes to anonymous function parameter types as well. This inference aims to provide the most specific type possible while obeying all of the existing constraints. The compiler does this by walking the hierarchy tree and finding the least upper bound. Let's look at an example: 

case class C(); class D(); case class E()

def iOrB(i: Int, s: Boolean)(b: Boolean): AnyVal = if (b) i else s
def iOrS(i: Int, s: String)(b: Boolean): Any = if (b) i else s

def sOrC(c: C, s: String)(b: Boolean): java.io.Serializable = if (b) c else s
def cOrD(c: C, d: D)(b: Boolean): AnyRef = if (b) c else d
def cOrE(c: C, e: E)(b: Boolean): Product with Serializable = if (b) c else e

Here, we specified the return types as the compiler infers them. For the first two cases, you can easily follow the hierarchy of Scala types to understand how the compiler did the inference. The last three are a bit more complicated:

  • In sOrC, the inferred type is java.io.Serializable. The reason for this is that Scala's String is just an alias for java.lang.String, which extends java.io.Serializable. All case classes in Scala extend Product with Serializable by default and Serializable extends java.io.Serializable. Therefore, java.io.Serializable is the least upper bound in this case.
  • In cOrDD is not a case class, and therefore it does not extend anything but the AnyRef, which becomes an inferred type.
  • In cOrE, both C and E are case classes, and so the compiler can infer the most specific type, that is, Product with Serializable.

In fact, the preciseness of the compiler can go quite far, as the following example demonstrates:

trait Foo { def foo: Int }
case class F() extends Foo {def foo: Int = 0}
case class G() extends Foo {def foo: Int = 0}

def fOrG(f: F, g: G)(b: Boolean):
Product with Serializable with Foo = if (b) f else g

Here, we can see that the inferred type of fOrG is a compound type with three members.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.225.57.164