{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "

Previous

\n", "

Next

\n", "

Tour of Scala

\n", "
\n", "\n", "# Type Inference\n", "\n", "The Scala compiler can often infer the type of an expression so you don't have to declare it explicitly.\n", "\n", "## Omitting the type" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "attributes": { "classes": [ "tut" ], "id": "" } }, "outputs": [ { "data": { "text/plain": [ "\u001b[36mbusinessName\u001b[39m: \u001b[32mString\u001b[39m = \u001b[32m\"Montreux Jazz Caf\\u00e9\"\u001b[39m" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "val businessName = \"Montreux Jazz Café\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The compiler can detect that `businessName` is a String. It works similarly with methods:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "attributes": { "classes": [ "tut" ], "id": "" } }, "outputs": [ { "data": { "text/plain": [ "defined \u001b[32mfunction\u001b[39m \u001b[36msquareOf\u001b[39m" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def squareOf(x: Int) = x * x" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The compiler can infer that the return type is an `Int`, so no explicit return type is required.\n", "\n", "For recursive methods, the compiler is not able to infer a result type. Here is a program which will fail the compiler for this reason:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "attributes": { "classes": [ "tut" ], "id": "" } }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "cmd2.sc:1: recursive method fac needs result type\n", "def fac(n: Int) = if (n == 0) 1 else n * fac(n - 1)\n", " ^Compilation Failed" ] }, { "ename": "", "evalue": "", "output_type": "error", "traceback": [ "Compilation Failed" ] } ], "source": [ "def fac(n: Int) = if (n == 0) 1 else n * fac(n - 1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It is also not compulsory to specify type parameters when [polymorphic methods](polymorphic-methods.ipynb) are called or [generic classes](generic-classes.ipynb) are instantiated. The Scala compiler will infer such missing type parameters from the context and from the types of the actual method/constructor parameters.\n", "\n", "Here are two examples:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "attributes": { "classes": [ "tut" ], "id": "" } }, "outputs": [ { "data": { "text/plain": [ "defined \u001b[32mclass\u001b[39m \u001b[36mMyPair\u001b[39m\n", "\u001b[36mp\u001b[39m: \u001b[32mMyPair\u001b[39m[\u001b[32mInt\u001b[39m, \u001b[32mString\u001b[39m] = \u001b[33mMyPair\u001b[39m(\u001b[32m1\u001b[39m, \u001b[32m\"scala\"\u001b[39m)\n", "defined \u001b[32mfunction\u001b[39m \u001b[36mid\u001b[39m\n", "\u001b[36mq\u001b[39m: \u001b[32mInt\u001b[39m = \u001b[32m1\u001b[39m" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "case class MyPair[A, B](x: A, y: B);\n", "val p = MyPair(1, \"scala\") // type: MyPair[Int, String]\n", "\n", "def id[T](x: T) = x\n", "val q = id(1) // type: Int" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The compiler uses the types of the arguments of `MyPair` to figure out what type `A` and `B` are. Likewise for the type of `x`.\n", "\n", "## Parameters\n", "\n", "The compiler never infers method parameter types. However, in certain cases, it can infer anonymous function parameter types when the function is passed as argument." ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "attributes": { "classes": [ "tut" ], "id": "" } }, "outputs": [ { "data": { "text/plain": [ "\u001b[36mres3\u001b[39m: \u001b[32mSeq\u001b[39m[\u001b[32mInt\u001b[39m] = \u001b[33mList\u001b[39m(\u001b[32m2\u001b[39m, \u001b[32m6\u001b[39m, \u001b[32m8\u001b[39m)" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Seq(1, 3, 4).map(x => x * 2) // List(2, 6, 8)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The parameter for map is `f: A => B`. Because we put integers in the `Seq`, the compiler knows that `A` is `Int` (i.e. that `x` is an integer). Therefore, the compiler can infer from `x * 2` that `B` is type `Int`.\n", "\n", "## When _not_ to rely on type inference\n", "\n", "It is generally considered more readable to declare the type of members exposed in a public API. Therefore, we recommended that you make the type explicit for any APIs that will be exposed to users of your code.\n", "\n", "Also, type inference can sometimes infer a too-specific type. Suppose we write:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "attributes": { "classes": [ "tut" ], "id": "" } }, "outputs": [ { "data": { "text/plain": [ "\u001b[36mobj\u001b[39m: \u001b[32mNull\u001b[39m = \u001b[32mnull\u001b[39m" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "var obj = null" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can't then go on and make this reassignment:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "attributes": { "classes": [ "tut" ], "id": "" } }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "cmd5.sc:1: type mismatch;\n", " found : Object\n", " required: Null\n", "val res5 = obj = new AnyRef\n", " ^Compilation Failed" ] }, { "ename": "", "evalue": "", "output_type": "error", "traceback": [ "Compilation Failed" ] } ], "source": [ "obj = new AnyRef" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It won't compile, because the type inferred for `obj` was `Null`. Since the only value of that type is `null`, it is impossible to assign a different value.\n", "

Previous

\n", "

Next

\n", "

Tour of Scala

\n", "
" ] } ], "metadata": { "kernelspec": { "display_name": "Scala (2.13)", "language": "scala", "name": "scala213" }, "language_info": { "codemirror_mode": "text/x-scala", "file_extension": ".scala", "mimetype": "text/x-scala", "name": "scala", "nbconvert_exporter": "script", "version": "2.13.1" } }, "nbformat": 4, "nbformat_minor": 4 }