Introduction to syntax and some simple examples of scala


1. Języki i środowiska przetwarzania danych rozproszonych Scala 1 Szymon Grabowski Based mostly on: C. Horstmann, Scala for the Impatient, 2012 M. Odersky et al., Programming in Scala, 2nd Ed., 2010 and 1 Łódź, 2016

2. Install (SBT is a build tool) scala -version // scala[.bat] – opens the REPL compiler: scalac scala> 12 * 11.9 res0: Double = 142.8 scala> :quit // or :q // ScriptDemo.scala println("Hello, Scala!") To execute a script: scala ScriptDemo.scala 2

3. val and var val (=value) is immutable var (=variable) is mutable If possible, prefer values over variables! val x = 5 Type inference: // x = 2 // ERROR! from the init with e.g. 5 Scala ‘knows’ val x1, x2 = 20 that our value is of type Int. Same with Double, String, Vector… Or: val x: Int = 5; val y: Double = -3.2; val anotherDouble = -3.2 val text = "Hello" // or: val text: String = "Hello" var x = 3.5; x = -1 3

4. Some more types Boolean: true | false val keyKnown = false val ok: Boolean = true Vector – a popular container scala.collection.immutable.Vector[…] val v = Vector(3, 2, 10, 5) var v2 = v.sorted val r1 = Range(5, 8) // 5, 6, 7 println(v2) val r2 = Range(5, 8).inclusive // v(0) = -1 // ERROR // 5, 6, 7, 8 v2 = v2.reverse // it’s a method call! println(v2) val v3 = v updated(1, 99) // Vector(3, 99, 10, 5) 4

5. Expressions An expression produces a result. E.g.: scala> val i = 4; i: Int = 4; scala> i + 3 res1: Int = 7 Watch this! Unit type: more or less equivalent to void in Java. 5

6. Brevity in Scala (some examples) • return keyword may be omitted (the last expression in a compound expression is the result) • semicolons may be omitted • type inference • parens in method calls may be omitted if zero or one argument follows – only in the so-called operator notation! • dot after the object name in method call may be omitted in the same case as above The last two listed rules in action: 3*4 One of my most productive days // It’s the same as: 3.*(4) was throwing away 1000 lines of code. / Ken Thompson, val ell = List(2, 3, 5, 7, 11) co-designer of Unix / print(ell head) // 2 6 Console print ell.head // 2

7. Scala’s best (from Java to Scala) case class Person(var firstName: String, var lastName: String) 7

8. Methods with no parameters As said, parens are then not needed. Yet, it’s good style to use () for a mutator method and drop the () for an accessor method. Even more: we can enforce this convention: class Counter { def current = value // no () } Now the invocation myCounter.current() is forbidden (only myCounter.current is correct). 8

9.On type inference 9

10. Are these two functions equivalent? def check1(x: Double) = if (x < 1.0 || x > 10.0) false else true def check2(x: Double) = if (x >= 1.0 && x <= 10.0) true else false Is check1(x) == check2(x) for any x? No. val x = Double.NaN // or: … = 0.0 / 0.0 print(check1(x), check2(x)) // (true,false) 10

11. Functions in Scala are objects Their type depends on how many arguments they have. E.g. Function2[Int, String, Boolean] (which extends AnyRef) means a 2-argument function (Int, String) => Boolean. A call f(3, "abc") will be expanded to f.apply(3, "abc"). Methods can be used as functions: if you write a method name where a Function object is required, the compiler will create a Function object for you. 11

12.Type hierarchy 12

13. A note on Scala types The Scala classes Any, AnyRef and AnyVal don’t appear as classes in bytecode, because of intrinsic limitations of the JVM. (in Java not everything is an object!). In Scala, on the other hand, everything is an object, all objects belong to a class, and they interact through methods. The JVM bytecode generated does not reflect this. So, in Scala, all objects are descendant from Any, and that includes both what Java considers objects and what Java considers primitives. Everything that is considered a primitive in Java is descendant from AnyVal in Scala. AnyRef in Scala is equivalent to java.lang.Object (on the JVM; on .NET it was an alias for System.Object). 13 what-are-the-relationships-between-any-anyval-anyref-object-and-how-do-they-m

14. The Java primitive types You can’t write: new Int(5) (nor Int(5), new Int etc.) in Scala. error: class Int is abstract; cannot be instantiated Int, Double etc. classes are abstract and final. The instances of these classes are all written as literals in Scala. Internally, Scala stores e.g. Ints are 32-bit integers, exactly like Java’s int values. Good for efficiency and interoperability with Java libraries. 14

15.Type Nothing inherits any other type Nothing != Unit. Nothing has no instances. 15

16. Lists Lists (like strings) are immutable. List has O(1) prepend and head/tail access. Most other operations (incl. index-based lookup, length, append) take O(n) time. 16

17. ‘cons’ operator Cons behavior is specific. Lists are constructed right-to-left. General rule: if an operator ends in : it is translated into a method call on the right operand. 17

18. Some operations on lists Indexing: list(0) Slicing: list.slice(1, 3); list.slice(2, list.last) Reversing: list.reverse Sorting: list.sorted Partitioning according to a predicate: partition (p : (A) => Boolean) : (List[A], List[A]) span (p : (A) => Boolean) : (List[A], List[A]) Returns the longest prefix of the list whose elements all satisfy the given predicate, and the rest of the list. => called informally a rocket operator 18

19. Some operations on lists, cont’d forall val list = List("boo", "woo", "woo") print(list forall(it => it endsWith "o")) // true print((list ::: "o!" :: Nil) forall(it => it endsWith "o")) // false exists val list = List(5, -3, 2, 1) print(list exists(x => x % 2 == 0)) // true They work for many other collections (and strings) too. (For maps, however, it’s probably much more efficient to use contains than exists.) val s = "STRING"; println(s forall Character.isUpperCase) // true 19

20. What is Nil? Nil is defined as: package scala.collection.immutable object Nil extends List[Nothing] with Product with Serializable List[A] is a covariant type (more on this later), which means that e.g. List[String] is a subtype of List[AnyRef], or List[Nothing] is a subtype of List[A] for any type A. Therefore, we don’t need to write Nil[A] for all types A! One Nil object is enough. 20 Dean Wampler & Alex Payne, Programming Scala, 2nd Ed., 2015, Chap. 10.

21. Extract Method (common refactoring technique) Example from: Can we always easily extract a method? (And what does it have to do with Scala?) If some variable from scalarProduct(…) changes in the supposed printScalarProduct(…), we are unlucky… In Scala: we could have e.g. val x: List[Int] = … (same with y, product) 21 and we’re safe from possible side-effects.

22. for loop for (y <- List(1, 2, 3)) { println(y) } for as an expression: 22

23.for loop: multiple filters possible, variable binding… for / yield = for comprehension 23

24. Operators Formally, there’s no “operator overloading” in Scala; e.g. + is “just a function/method”. Yet, there are some things to remember… If a plain (method/function or var) identifier starts with a letter or _, it cannot contain operator symbols (+-*/< etc.). E.g. val xyz++= = 1 won’t compile. Operators have priorities and associativity. 2+3*28 but 2.+(3).*(2)  10 !! (2.+(3) * 2 == 10 too) 2 + 3.*(2) == 8 (conclusion: the period binds earlier than e.g. + or *). Priority depends on the first (leftmost) symbol of an operator, while associativity on the last (rightmost) symbol. 24

25. Creating an operator function def ~=(x: Double, y: Double, precision: Double) = { if ((x - y).abs < precision) true else false } scala> val a = 0.3 a: Double = 0.3 scala> val b = 0.1 + 0.2 b: Double = 0.30000000000000004 scala> ~=(a, b, 0.0001) res0: Boolean = true 25 Alvin Alexander, Scala Cookbook, 2013. Chap. 2.5.

26. Infix operators Any method with 1 param can be used as an infix operator. Now we can define xor like this: More traditionally, it would be like: def xor(x: MyBool, y: MyBool) = x.or(y).and(x.and(y).negate) 26

27. Arrays are mutable There are mutable and immutable versions of many reference types in Scala. If possible, use immutable ones! 27

28. Hints on arrays Multi-dim array: val a = Array.ofDim[Int](3, 2) 28

29.ArrayBuffer is equivalent of java.util.ArrayList Conversions to Array/ArrayBuffer: 29 b.toArray, a.toBuffer