Getting Started with Scala 13 Dec21 Getting Scala

  • Slides: 33
Download presentation
Getting Started with Scala 13 -Dec-21

Getting Started with Scala 13 -Dec-21

Getting Scala n Download Scala. IDE: http: //scala-ide. org/ n n This is a

Getting Scala n Download Scala. IDE: http: //scala-ide. org/ n n This is a customized version of Eclipse Already using Eclipse? It’s okay to have more than one version Scala can also be obtained by itself: http: //www. scala-lang. org/downloads You can use the Scala documentation online, http: //www. scala-lang. org/downloads or download it and use it locally, http: //www. scala-lang. org/downloads n n Documentation is not always complete or easy to read The source is directly available from the documentation

Hello World n n n /** Everybody's first program */ object Hello. World {

Hello World n n n /** Everybody's first program */ object Hello. World { def main(args: Array[String]) { println("Hello, World!") } } Save on a file named Hello. World. scala Compile with scalac Hello. World. scala (or from your IDE) Run with scala Hello. World (or from your IDE) Generate documentation with scaladoc Hello. World. scala The above code creates a singleton object n n n Everything in the object is like Java’s static Scala doesn’t have static Scala does have classes; we’ll get to those later 3

Comments n n // and /*. . . */ comments are as in Java

Comments n n // and /*. . . */ comments are as in Java /** Scaladoc comments are similar to Javadoc * comments. As in Javadoc, the first sentence * is a summary sentence, and additional * sentences give more detail. However, the * formatting convention is slightly different, * and wiki markup may be used instead of * HTML markup. Most of the same flags * (@author, etc. ) are used. */ def do. Nothing = ()

Types n The type hierarchy is a lattice, not a tree n n That

Types n The type hierarchy is a lattice, not a tree n n That is, it has a “bottom” as well as a “top” Any n Any. Val n n n Any. Ref (corresponds to Object in Java) n n Boolean, Char, Byte, Short, Int, Long, Float, Double n Scala has no primitives—these are objects Unit (has only a single value, () n Unit is returned by functions that “don’t return anything” (e. g. println) All Java reference types, for example, String Scala. Object n All Scala reference types, including Array and List Null (bottom of all Any. Ref objects) Nothing (bottom of Any) 5

Declaring variables and values n The syntax is var name: type = value //

Declaring variables and values n The syntax is var name: type = value // declares a variable val name: type = value // declares a value Values are immutable: they can’t be changed The : type can almost always be left off—the type is inferred from the value The = value must (almost) always be supplied This also works: var x: Double = 5 Style rule: use val instead of var wherever you can n Rules for alphanumeric names are just like in Java n n n n n But there are other kinds of names Scope rules are almost the same as those in Java Capitalization conventions are just like in Java Arithmetic, comparison, and logical operators are just like in Java Indentation is 2 spaces, not 4, but is otherwise like Java 6

“Statements” n n Scala’s “statements” should really be called “expressions, ” because every statement

“Statements” n n Scala’s “statements” should really be called “expressions, ” because every statement has a value The value of many statements, for example the while loop, is () n n n The value of a if or match statement is the last value computed The value of a block, {…}, is the last value computed in the block A statement is ended by the end of the line (not with a semicolon) unless it is obviously incomplete, or if the next line cannot begin a valid statement n n n () is a value of type Unit () is the only value of type Unit () basically means “Nothing to see here. Move along. ” For example, x = 3 * (2 * y + is obviously incomplete Because Scala lets you leave out a lot of unnecessary punctuation, sometimes a line that you think is complete really isn’t complete (or vice versa) You can end statements with semicolons, but that’s not good Scala practice 7

Familiar statement types n These are the same as in Java, but have a

Familiar statement types n These are the same as in Java, but have a value of ( ): n n variable = expression // also +=, *=, etc. while (condition) { statements } do { statements } while (condition) These are the same as in Java, but may have a useful value: n { statements } n n if (condition) { statements } else { statements } n n n The value is the value of whichever block is chosen If the value is to be used, both blocks should have the same type, otherwise the type of the result is the “least upper bound” of the two types if (condition) { statements } n n The value of the block is the last value computed in it The value is the value of the last statement executed, but its type is Any – if you want a value, you really should use an else As in Java, braces around a single statement may be omitted 8

The for comprehension n Scala’s for is much more powerful than Java’s for n

The for comprehension n Scala’s for is much more powerful than Java’s for n n n We will just cover some simple cases here for (i <- 1 to 10) { println(i) } n n Prints all the values in my. Array for (x <- my. Array) { println(x) } n n Prints the numbers 1 through 9 for (x <- 0 until my. Array. length) { println(my. Array(x)) } n n Prints the numbers 1 through 10 for (i <- 1 until 10) { println(i) } n n Consequently, it is used much more often than the other kinds of loops Prints all the values in my. Array for (x <- my. Array if x % 2 == 0) { println(x) } n Prints all the even numbers in my. Array

Arrays n Arrays in Scala are parameterized types n n n When no initial

Arrays n Arrays in Scala are parameterized types n n n When no initial values are given, new is required, along with an explicit type: n n Array[String] is an Array of Strings, where String is a type parameter In Java we would call this a “generic type” val ary = new Array[Int](5) When initial values are given, new is not allowed: n val ary 2 = Array(3, 1, 4, 1, 6) n Array syntax in Scala is just object syntax n Scala’s Lists are more useful, and used more often, than Arrays n n val list 1 = List(3, 1, 4, 1, 6) val list 2 = List[Int]() // An empty list must have an explicit type

Multidimensional arrays n To create a 2 -dimensional array or higher, you need to

Multidimensional arrays n To create a 2 -dimensional array or higher, you need to use the to. Dim method n n scala> val two. Dim = Array. of. Dim[Int](2, 3) two. Dim: Array[Int]] = Array(0, 0, 0), Array(0, 0, 0)) Once created, it’s used very much like an array in Java (but with parentheses rather than brackets) n n scala> two. Dim(1)(2) = 99 scala> two. Dim res 2: Array[Int]] = Array(0, 0, 0), Array(0, 0, 99))

Simple List operations n By default, Lists, like Strings, are immutable n n Basic

Simple List operations n By default, Lists, like Strings, are immutable n n Basic operations: n n n n n list. head (or list head) returns the first element in the list. tail (or list tail) returns a list with the first element removed list(i) returns the ith element (starting from 0) of the list(i) = value is illegal (immutable, remember? ) value : : list returns a list with value appended to the front list 1 : : : list 2 appends (“concatenates”) the two lists list. contains(value) (or list contains value) tests whether value is in list Many operations on Lists also work on other kinds of Sequences An operation on a Sequence may return a Sequence of a different type n n n Operations on an immutable List return a new List scala> "abc" : : List(1, 2, 3) res 22: List[Any] = List(abc, 1, 2, 3) This happens because Any is the only type that can hold both integers and strings There are over 150 built-in operations on Lists—use the API!

for…yield n for returns Unit, but for…yield returns a sequence of values n n

for…yield n for returns Unit, but for…yield returns a sequence of values n n Where possible, it returns the same type of sequence as it operates on scala> for (i <- List(1, 2, 3)) yield { 2 * i } res 1: List[Int] = List(2, 4, 6) scala> for (i <- 97 to 100) yield { i. to. Char } res 2: scala. collection. immutable. Indexed. Seq[Char] = Vector(a, b, c, d) scala> for (ch <- "abcd" if ch != 'c') yield { ch. to. Int } res 3: scala. collection. immutable. Indexed. Seq[Int] = Vector(97, 98, 100)

Tuples n Scala has tuples, up to size 22 (why 22? I have no

Tuples n Scala has tuples, up to size 22 (why 22? I have no idea. ) n n n Tuples are referenced starting from 1, using _1, _2, . . . n n scala> val t = Tuple 3(3, "abc", 5. 5) t: (Int, java. lang. String, Double) = (3, abc, 5. 5) scala> val tt = (3, "abc", 5. 5) tt: (Int, java. lang. String, Double) = (3, abc, 5. 5) scala> val t = ('a', "one", 1) t: (Char, String, Int) = (a, one, 1) scala> t. _2 res 3: String = one Tuples, like Lists, are immutable Tuples are a great way to return more than one value from a method

An aside. . . abbreviations n Scala lets you omit a lot of “unnecessary”

An aside. . . abbreviations n Scala lets you omit a lot of “unnecessary” punctuation n n For example, if (name starts. With "Dr. ") {. . . } is more readable (and easier to type) than if (name. starts. With("Dr. ")) {. . . } Readability matters! Therefore, you should experiment with leaving out punctuation anywhere you think it might be okay However, n If you get mysterious syntax errors, try putting the punctuation back in, both on this line and on the previous line

Maps n scala> val m = Map("apple" -> "red", "banana" -> "yellow") m: scala.

Maps n scala> val m = Map("apple" -> "red", "banana" -> "yellow") m: scala. collection. immutable. Map[java. lang. String, java. lang. String] = Map((apple, red), (banana, yellow)) n n n Notice that a Map is really just a list of Tuples The -> is provided as a more readable syntax scala> m("banana") res 2: java. lang. String = yellow scala> m contains "apple" res 3: Boolean = true scala> m("cherry") java. util. No. Such. Element. Exception: key not found: cherry

Simple method definitions n def is. Even(n: Int) = { val m = n

Simple method definitions n def is. Even(n: Int) = { val m = n % 2 m == 0 } n n n def is. Even(n: Int) = n % 2 == 0 n n n The result is the last value (in this case, a Boolean) This is really kind of poor style; the extra variable isn’t needed This is much better style The result is just a single expression, so no braces are needed def count. To(n: Int) { for (i <- 1 to 10) { println(i) } } n n n It’s good style to omit the = when the result is () If you omit the =, the result will be () You need either braces or an =; you can’t leave out both

More method definitions n def half(n: Int): Double = n / 2 n n

More method definitions n def half(n: Int): Double = n / 2 n n n You can state the result type explicitly In this example, half(7) will return 3. 5 (!) def half(n: Int): Int = return n / 2 n n If you use a return statement, you must state the result type explicitly Good style in Scala is to avoid using return statements, and just putting the return value as the last thing in the method

Methods and functions n A method is a function that belongs to an object

Methods and functions n A method is a function that belongs to an object n n A function does not belong to any object n n n Methods usually use, and manipulate, the fields of an object The inputs to a function are, or should be, just its parameters The result of calling a function is, or should be, just its return value Scala can sometimes accept a method where a function is expected n A method can sometimes be “converted” to a function by following with an underscore (for example, is. Even _)

Functions are first-class objects n n n Functions are values (like integers, etc. )

Functions are first-class objects n n n Functions are values (like integers, etc. ) and can be assigned to variables, passed to and returned from functions, and so on Wherever you see the => symbol, it’s a literal function Example (assigning a literal function to the variable foo): n scala> val foo = (x: Int) => if (x % 2 == 0) x / 2 else 3 * x + 1 foo: (Int) => Int = <function 1> scala> foo(7) res 28: Int = 22 n n The basic syntax of a function literal is parameter_list => function_body In this example, foreach is a function that takes a function as a parameter: n my. List. foreach(i => println(2 * i))

Functions as parameters n n To define a function, you must specify the types

Functions as parameters n n To define a function, you must specify the types of each of its parameters Therefore, to have a function parameter, you must know how to write its type: n n (type 1, type 2, . . . , type. N) => return_type // if only one parameter () => return_type // if no parameters Example: n scala> def do. Twice(f: Int => Int, n: Int) = f(f(n)) do. Twice: (f: (Int) => Int, n: Int)Int scala> def collatz(n: Int) = if (n % 2 == 0) n / 2 else 3 * n + 1 collatz: (n: Int)Int scala> do. Twice(collatz, 7) res 2: Int = 11 scala> do. Twice(a => 101 * a, 3) res 4: Int = 30603

Higher-order methods on Lists n map applies a one-parameter function to every element of

Higher-order methods on Lists n map applies a one-parameter function to every element of a List, returning a new List n n n scala> def double(n: Int) = 2 * n double: (n: Int)Int scala> val ll = List(2, 3, 5, 7, 11) ll: List[Int] = List(2, 3, 5, 7, 11) scala> ll map double res 5: List[Int] = List(4, 6, 10, 14, 22) scala> ll map (n => 3 * n) res 6: List[Int] = List(6, 9, 15, 21, 33) scala> ll map (n => n > 5) res 8: List[Boolean] = List(false, true) filter applies a one-parameter test to every element of a List, returning a List of those elements that pass the test n n scala> res 10: scala> once res 11: ll filter(n => n < 5) List[Int] = List(2, 3) ll filter (_ < 5) // abbreviated function where parameter is used List[Int] = List(2, 3)

More higher-order methods n def filter. Not(p: (A) => Boolean): List[A] n n def

More higher-order methods n def filter. Not(p: (A) => Boolean): List[A] n n def count(p: (A) => Boolean): Int n n Tests whether a predicate holds for at least one of the elements of this list def find(p: (A) => Boolean): Option[A] n n Tests whether a predicate holds for every element of this list def exists(p: (A) => Boolean): Boolean n n Counts the number of elements in the list which satisfy a predicate def forall(p: (A) => Boolean): Boolean n n Selects all elements of this list which do not satisfy a predicate Finds the first element of the list satisfying a predicate, if any def sort. With(lt: (A, A) => Boolean): List[A] n Sorts this list according to a comparison function

Explicit pattern matching n Explicit pattern matching is done with the match method: expression

Explicit pattern matching n Explicit pattern matching is done with the match method: expression match { case pattern 1 => expressions … case pattern. N => expressions }

Pattern matching n Pattern matching on literal values: n n today match { case

Pattern matching n Pattern matching on literal values: n n today match { case "Saturday" => println("Party!") case "Sunday" => println("Pray. . ") case day => println(day + " is a workday. : ( ") } Pattern matching on types: n something match { case x: Int => println("I'm the integer " + x) case x: String => println("I'm the String "" + x + """) println("My length is " + x. length) case _ => println("I don't know what I am! : ( ") }

The Option type n n Scala has null because it interoperates with Java; it

The Option type n n Scala has null because it interoperates with Java; it shouldn’t be used any other time Instead, use an Option type, with values Some(value) and None n n def max(list: List[Int]) = { if (list. length > 0) { val big = list reduce {(a, b) => if (a > b) a else b} Some(big) } else { None } max(my. List) match { case Some(x) => println("The largest number is " + x) case None => println("There are no numbers here!!!") }

The require and assert methods n n require and assert are methods that throw

The require and assert methods n n require and assert are methods that throw an exception when their argument is false require is used to document something that must be true in order for the code to work n n n def sqrt(x: Double) = { require(x >= 0); . . . } require is often used at the beginning of a method assert is used to document something that you “know” to be true n n take. Cis 554 course assert(languages. IKnow contains "Scala") assert is often used as “executable documentation”

The ensuring method n The ensuring method applies a predicate to a value and,

The ensuring method n The ensuring method applies a predicate to a value and, if the predicate result is true, returns the value, otherwise throws an Assertion. Error n n n n Syntax: value ensuring(predicate) scala> 12 ensuring(true) res 1: Int = 12 scala> 12 ensuring(_ > 10) res 2: Int = 12 scala> def twice(x: Int) = 2 * x ensuring(_ > 0) twice: (x: Int)Int scala> twice(3) res 3: Int = 6 scala> twice(-5) java. lang. Assertion. Error: assertion failed (+ many lines) ensuring can be useful to guarantee the result of a method n Always use _ in the predicate to represent the method’s return value

Dealing with exceptions n Scala’s exception creation and throwing is like Java: n n

Dealing with exceptions n Scala’s exception creation and throwing is like Java: n n n class Rotten. Egg. Exception extends Exception throw new Rotten. Egg. Exception Catching a thrown exception uses pattern matching: n try { make. An. Omlet } catch { case ex: Rotten. Egg. Exception => println("#$%&#@") case ex: Exception => println("What went wrong? ") }

Console I/O n n n val data = read. Line // Reads a single

Console I/O n n n val data = read. Line // Reads a single line from the Console print(data) newline // Prints to the Console without a println(data) newline // Prints to the Console with a

File I/O n object Test. IO { def main(args: Array[String]) { println("Testing file I/O")

File I/O n object Test. IO { def main(args: Array[String]) { println("Testing file I/O") import java. io. _ import scala. io. Source val file = new File("testio. txt") val writer = new Print. Writer(file) writer write "firstrn" writer write "second" writer. close() n n n Use correct case for file names (only Windows ignores case) Use forward slashes, /, in paths, which work on any platform, not backslashes, , which work only on Windows, Mac, and Linux have different end-of-line codes (rn is Windows), and this causes problems val lines = Source. from. File(file). get. Lines(). to. List println(lines) } n } Testing file I/O List(first, second)

Use the source, Luke n n n Books and tutorials are good for learning

Use the source, Luke n n n Books and tutorials are good for learning the syntax of Scala, but they aren’t much help learning the API Unfortunately, Scala’s API documentation isn’t very complete The good news is, it’s easy to get to the source code—and in most cases, the source code is easier to read than you might think

The End 33

The End 33