{ "cells": [ { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "
\n", "

Scala - the basics

\n", "

Marcel Lüthi
Departement of Mathematics and Computer Science

\n", "
" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Why Scala?\n", "\n", "![why-scala](images/why-scala.png)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Python\n", "\n", "#### Advantages \n", "+ Easy to learn\n", "+ Elegant\n", "+ Ubiquitous\n", "\n", "#### Disadvantages\n", "- Brittle for large programs\n", " * designed for scripting\n", " * no static types\n", "- (Slow)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "\n", "> Solution: Write core in C++ " ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Python with C++ core\n", "\n", "#### Advantages\n", "- Easy to use (through Python) and fast\n", "- Can scale to huge programs\n", "\n", "#### Disadvantage\n", "\n", "- Difficult to program / maintain (C++)\n", "- Difficult to deploy (C++)\n", "- Serious researchers need to learn 2 languages" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "> - C++ alone more complicated than Scala. Combination makes things worse! " ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Scala - A scalable language\n", "\n", "> Good to experiment - possible to scale\n", "\n", "* Modern \n", " * but with good ecosystem\n", "* Elegant - clean concepts\n", "* Open source\n", "* Platform independent\n", "* Interoperable with Java\n", "* Statically typed\n", "* Fusion of object-oriented and functional" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Scala \n", "\n", "* Academic roots\n", " * built on well founded theoretical concepts\n", "\n", "* Concepts not difficult but need to be learned\n", "\n", "\n", "\n", "> Learning concepts makes you a better programmer" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Example Scala program\n", "\n", "
\n",
    "object Example {\n",
    "  \n",
    "    abstract class Tree\n",
    "    case class Branch(left: Tree, right: Tree) extends Tree\n",
    "    case class Leaf(x: Int) extends Tree\n",
    "\n",
    "    val tree1 = Branch(Branch(Leaf(1), Leaf(2)), Branch(Leaf(3), Leaf(4)))\n",
    "\n",
    "    def sumLeaves(t: Tree): Int = t match {\n",
    "        case Branch(l, r) => sumLeaves(l) + sumLeaves(r)\n",
    "        case Leaf(x) => x\n",
    "    }\n",
    "\n",
    "    println(\"sum of leafs=\" + sumLeaves(tree1))       \n",
    "}\n",
    "
" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Basics of Scala\n", "\n", "Slides are loosely based on \n", "* [Essential scala](https://underscore.io/training/courses/essential-scala/) the delightful and free book on Scala\n", "* [Essential essential Scala](https://github.com/underscoreio/eescala) (online slides)\n", "by Noel Welsh and Dave Gurnell.\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Expressions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* Expressions are program text\n", "* Expressions evaluate to values\n", "* Expressions have a type" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "(5 + 3) * 8" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "List(1,2,3).toString\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Values\n", "\n", "* Expressions can be named using ```val```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "val myCalculation = (5 + 3) * 8 " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "val myExtendedCalculation = myCalculation * 10" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Types\n", "\n", "* Every expression has a type" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "val a : Int = (5 + 3) * 8" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "val b = ((5 + 3 ) * 8).toString" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true, "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "val c : String = (5 + 3 ) * 8" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Expression, types and values\n", "\n", "![expression-types-values](./images/expression-types-values.png)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Blocks\n", "\n", "* Sequence of expressions\n", "* Last line is result of block \n", " * Block is itself expression" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "{\n", " val x = 1 + 1\n", " x + 1\n", "}" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Blocks\n", "\n", "* Blocks are expressions - can be named" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "val result = {\n", " val x = 1 + 1\n", " x + 1\n", "}" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Blocks \n", "\n", "* Can be placed everywhere an expression is required" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "println( { val x = 1 + 1\n", " x + 1} ) " ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Functions\n", "\n", "* Expressions that take parameter\n", "\n", "![functions](./images/functions.png)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Functions " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "(x : Int) => x + 3" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "* Function body can be a block (as block is expression)" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [ { "data": { "text/plain": [ "\u001b[36mres5\u001b[39m: \u001b[32mInt\u001b[39m => \u001b[32mInt\u001b[39m = ammonite.$sess.cmd5$Helper$$Lambda$3763/1257149155@7b903bac" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "(x : Int) => {\n", " val y = 1\n", " x + y\n", "} \n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Functions\n", "\n", "* Functions are expressions, hence values" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "val f = (x : Int) => {\n", " val y = 1\n", " x + y\n", "} \n", "\n", "f(3)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Types of a function" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* Type of a function\n", " * ```A => B```: map a value of type ```A``` to a value of type ```B```" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\u001b[36mf\u001b[39m: \u001b[32mInt\u001b[39m => \u001b[32mInt\u001b[39m = ammonite.$sess.cmd6$Helper$$Lambda$3767/474480687@1ceb390c" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "val f : Int => Int = (x : Int) => {\n", " val y = 1\n", " x + y\n", "}" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Exercises\n", "\n", "* Create the function ```square``` which takes a number ```x``` (of type ```Double```) and returns $x \\cdot x$.\n", "* Create a function ```sumOfSquares``` which takes two arguments ```x``` and ```y``` and returns $x^2 + y^2$.\n", "* Can you create a function ```apply twice```, which takes a function ```f``` of type ```Double => Double``` and a number ```x``` of type ```Double``` as parameters and returns ```f(f(x)```?\n", "* Can you create a function ```compose```, which takes two functions $f$ and $g$ as a parameter and returns the composition of f and g, i.e. $f \\circ g := f(g(x))$?" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Methods\n", "\n", "\n", "![methods](./images/methods.png)\n", "\n", "> Similar to functions, but with special syntax" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "def add(x : Int, y : Int) = x + y\n", "\n", "add(5, 3)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Classes\n", "\n", "* Similar to Java \n", " * Main difference: Argument list as constructor\n", " * ```val ``` before argument: variable is public" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "defined \u001b[32mclass\u001b[39m \u001b[36mMyClass\u001b[39m" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "class MyClass(field1 : String, val field2 : Int) {\n", " def printOut() : Unit = {\n", " println(field1 + \", \" +field2)\n", " }\n", "}" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "abc, 5\n" ] }, { "data": { "text/plain": [ "\u001b[36mmyClass\u001b[39m: \u001b[32mMyClass\u001b[39m = ammonite.$sess.cmd14$Helper$MyClass@6b4fac02" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "val myClass = new MyClass(\"abc\", 5)\n", "myClass.printOut()" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Case classes\n", "\n", "* Special classes for organizing data\n", " * Ensure proper equality\n", " * Do not need new keyword\n", " * constructor arguments are public by default" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "case class Point(x : Double, y : Double)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "val p = Point(3, 5)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Objects\n", "\n", "* Whenever only a single instance is needed\n", "* Often associated to class with same name\n", " * Called *companion object*\n", " \n", "```scala\n", "class PositiveNumber(num : Int) { \n", " // some methods\n", "}\n", "\n", "object PositiveNumber {\n", " val MaxValue : Int = java.lang.Integer.MAX_VALUE\n", " val MinValue : Int = 0\n", "}\n", "```" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Exercises:\n", "\n", "* Create a class ```Vector2D```, which represents a vector in two dimensional space.\n", " * Implement the method ```plus```, which adds two vectors and returns a new vector. \n", " * Implement the method ```dot```, which computes the scalar product\n", " * Create two instances of the Vector $(0, 1)$ and compare them for equality. \n", " * Define the class once as a case class and once as a normal class. What is the difference?" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Parametric types\n", "\n", "> Types in Scala can be parametric\n", "\n", "```scala\n", "case class Pair[A, B](first : A, second : B)\n", "```\n", "\n", "Usage:\n", "```scala\n", "val pair1 = Pair(3, 5.0) \n", "val pair2 : Pair[String, Int] = Pair(\"abc\", 5)\n", "```\n", "\n", "\n", "* Types are inferred automatically when possible\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Parametric types\n", "\n", "> Methods can be parametric\n", "\n", "```scala\n", "def first[A, B](pair : Pair[A, B]) : A = pair.first\n", "\n", "val pair = Pair(3, 5.0)\n", "first(pair)\n", "```" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Pattern matching\n", " \n", " * Generalizes switch/case statement from java\n", " \n", "```scala\n", "expression match { \n", " case pattern1 => expression1 \n", " case pattern2 => expression2 \n", " // ...\n", "}\n", "```\n", " " ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Pattern matching" ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [ { "data": { "text/plain": [ "\u001b[36mres\u001b[39m: \u001b[32mAny\u001b[39m = \u001b[32m\"two\"\u001b[39m" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "val res = 2 match { \n", " case 1 => \"one\" \n", " case 2 => \"two\" \n", " case _ => 5\n", "} " ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "defined \u001b[32mfunction\u001b[39m \u001b[36mmatchTest2\u001b[39m\r\n", "\u001b[36mres20_1\u001b[39m: \u001b[32mInt\u001b[39m = \u001b[32m55\u001b[39m" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def matchTest2(x: Any): Int = x match { \n", " case 1 => 1\n", " case \"two\" => 2 \n", " case y: Int => y\n", " case _ => 99\n", "} \n", "matchTest2(55)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Next time - Scala, the simple parts\n", "\n", "> How these concepts fit together" ] } ], "metadata": { "celltoolbar": "Slideshow", "kernelspec": { "display_name": "Scala", "language": "scala", "name": "scala" }, "language_info": { "codemirror_mode": "text/x-scala", "file_extension": ".sc", "mimetype": "text/x-scala", "name": "scala", "nbconvert_exporter": "script", "version": "2.13.1" }, "livereveal": { "transition": "none" } }, "nbformat": 4, "nbformat_minor": 2 }