======= Scala @ PP ======= ===== "Meta ideas" ===== Test-driven development ===== 1. Installation ===== ===== 2. Syntax ===== 2.1. Writing functions 2.2. Function evaluation (order of parameters in function call matters !) - using the ''=>'' to delay evaluation 2.3. Conditionals - '' def f(x : Int) = if (x >= 0) x else -x'' - boolean expressions (''true'', ''false'', ''!b'', ''&&'', ''||'') - the "by value" definition using ''val'' - example using def and val against a loop Newton square root estimation * Blocks - expressions in Scala * visibility of variables in blocks * local scoping (similar to let) * semicolons (optional) * tail recursion in Scala (only direct recursive calls are optimised @tailrec) * function types (''f : Int => Int'') * anonymous functions (''(x: Int, y: Int) => x + y'', '' x => x+x'') * currying (''def f(x: Int, y: Int)(z: Int):Int = x+y+z'') * higher-order functions (mapReduce implementation) * classes and **methods** class Rational(x: Int, y: Int) { // creates a Type as well as a constructor for the new type def a = x def b = y } val r = new Rational(1,2) * ''toString'' and ''@override'' * the ''require'' (a precondition on the caller of a function) (equivalent to) and ''assert'' (check the code is right) * **constructors**: * multiple constructors: class ... { def this(x: Int) = this(x,1) } * infix notation for functions r add s /*same as*/ r.add(s) def < (param : Rational) /* symbolic identifiers may contain operator symbols */ def unary_- (...) /* to overload negation. Careful, white spaces can be interpreted as identifiers */ /* the precedence of an operator is determined by its first character */ /* precedence cannot be overridden by the programmer */ ===== 3. Data representation ====== * object definitions - singleton classes ''object Empty extends IntSet'' * companion objects (one object per class) * annotation ''@main def birthday'' - can be called directly from compilation ''scala birthday ...'' * ''println(s"Hello $name")'' * **dynamic binding** * packages - organising sources - directories (not enforced by the fs) import pack.Obj * traits (similar to interfaces in Java, but can have parameters, contain fields and defined functions) * object hierarchy in Scala * exceptions (similar to Scala) * **ADTs**: * ''class Cons (val head: Int, val tail: List) extends... '' - value parameters * type parameters (square brackets) * generic functions ''def singleton[T] (elem: T) ...'' * **Scala is a pure OO language (unlike Java)!!** * functions are implemented as objects trait Function1 [A,B]: def apply(x: A): B f = new Function1[Int,Int]: //anonymous class def apply(x: Int) = x * x /* anonymous classes are equivalent to blocks that evaluate to an object*/ { class $anonfun() extends Function1[Int,Int]: def apply(x: Int) = x * x $anonfun() def f(x: Int): Boolean = ... /* the above is not itself a function value. However, if it is used where a Function type is expected it is converted automatically to the function value: */ (x: Int) => f(x) // or expanded to new Function[Int, Boolean]: def apply(x: Int) = f(x) ===== 4. TDAs ====== Object-Oriented decomposition (the classical TDAs vs OO) Functional decompositions (case classes) def eval(e: Expr): Int = e match case Number(n) => n case Sum(e1,e2) => eval(e1) + eval(e2) val l = 1 :: 2 :: 3 :: Nil **Enums** (TDAs) enum Expr: case Var (s: String) case Number (n: Int) case Sum(e1: Expr, e2: Expr) case Prod(e1: Expr, e2: Expr) Type bounds in generics def asseertAllPos [S <: IntSet] (r: S): S = ...