An Introduction to Scala Andreas Neumann, Senior Software Engineer! a.neumann@clueda.com
Overview ⬤A very short history of Scala! ⬤Using Scala - Basics: Compile and run! ⬤Introduction to the core concepts : vals, classes, objects, traits, control structures and functions! ⬤Some intermediate concepts in Scala: Pattern Matching, Option, XML, Futures! ⬤Patterns in Scala! ⬤Functional Style Clueda AG 2
About Scala ⬤A JVM Languge! ⬤multiparadigmatic! ⬤functional object orientated Clueda AG 3
The father of Scala - Martin Odersky ⬤Professor EPFL! ⬤Java-Compiler! ⬤Java 1.4 Generics! ⬤PIZZA! ⬤Scala! ⬤Co-Founder Typesafe Clueda AG 4
The company behind Scala - ⬤Training! ⬤Consulting! ⬤Scala! ⬤Actor! ⬤Play Clueda AG 5
Who is using Scala ⬤Xerox! ⬤Twitter! ⬤Foursquare! ⬤Sony! ⬤Siemens! ⬤clueda! ⬤… Clueda AG 6
Nice features ⬤Can be integrated in any Java based architecture! ⬤support concurrent and asynchronous operations out of the box in many flavors (Futures,Parallel Collections, Akka)! ⬤great for embedded DSLs Clueda AG 7
Introduction ⬤Run code / compile Code! ⬤Syntax (some tips)! ⬤declare variables! ⬤functions! ⬤clases, traits and objects Clueda AG 8
Run code, compile sources ⬤Scala can be used in many different environments:! ⬤compile and run on a JVM! ⬤run as a script! ⬤in an interactive console, called REPL Clueda AG 9
Scala - compiler / scalac ⬤the compiler is called scalac! ⬤The sources are compiled to Java byte code! ⬤*.class! ⬤run class with scala <name> Clueda AG 10
Scripting with Scala - Unix ⬤Scala can be used as scripting language! ⬤change mode to executeable or run by bash Clueda AG 11 #!/bin/sh exec scala "$0" "$@" !# ! object HelloWorld { def main(args: Array[String]) { println("Hello, world! " + args.toList) } } HelloWorld.main(args)
Scripting with Scala - Windows ⬤Resembles UNIX use a batch script instead! ⬤*.bat! ⬤run Clueda AG 12 ::#!! @echo off! call scala %0 %*! goto :eof! ::!#! ! object HelloWorld {! def main(args: Array[String]) {! println("Hello, world! " +! args.toList)! }! }! ! HelloWorld.main(args)
Scala - Interpreter / REPL ⬤part of the scala installation! ⬤Start by typing scala the shell! ⬤:q or CTRL + d to quit Clueda AG 13 neumann@mac ~> scala! !! Welcome to Scala version 2.11.1 (Java HotSpot(TM) ! 64-Bit Server VM, Java 1.7.0_55).! Type in expressions to have them evaluated.! Type :help for more information.! ! scala> println("Hello World")! Hello World! ! scala> :q! !! neumann@mac ~>
Online REPL ⬤https://codebrew.io/ Clueda AG 14
Syntax ⬤No need for „;“ , one expression per line ! ⬤Still possible to add ; if for example you want several expression within one line! ⬤The dot on method invocations can be dropped. It is best practice to do so with infix invocation but not with postfix operations. Clueda AG 15 "Hallo Welt !".split(" ")! //res0: Array[String] = Array(Hallo, Welt, !)! ! scala> "Hallo Welt !" split " " ! //res2: Array[String] = Array(Hallo, Welt, !) scala> List(1,2.3).map(_ * 3).head! //res3: Double = 3.0! ! scala> ( List(1,2.3) map (_ * 3) ).head! //res4: Double = 3.0
val, vars ⬤val creates a Value which is not changeable ( like final modifier in Java)! ⬤var creates a Variable , which can be reassigned different values Clueda AG 16
Example: val and var Clueda AG 17 val x = 42! //x: Int = 42! ! var y = 99! //y: Int = 99! ! y = 1! y: Int = 1! ! x = 1! error: reassignment to val! x = 1! ^
Types and type inferrence ⬤Types are introduced after : which is written behind the var/val! ! ⬤Giving the type explicitly is optional as the type inference can infer the type. It’s considered good style to add the type information nonetheless. Clueda AG 18 s : String = "ein String" val a = "Hallo"! //a: java.lang.String = Hallo! ! val b = 1! //b: Int = 1! ! val c = 3.5! //c: Double = 3.5! ! val d = List(1,2.0)! //d: List[Double] = List(1.0, 2.0)
define methods ⬤methods are introduced with def! ⬤optionally there can be a list of parameters enclosed by parentheses! ⬤then the body of the function! ⬤methods returning a value put a between name arguments and the body! ⬤the result of the last expression evaluated within the body is the return value Clueda AG 19 def write(aString: String):Unit= {! println(aString) ! }! ! write("Hallo ihr alle da draußen!")! //Hallo ihr alle da draußen! def add(x: Int, y:Int) : Int = { ! x + y! }! ! add(40,2)! //res0: Int = 42
Collections ⬤Scala has a big Collections library! ⬤Collections provide similar interfaces as far as possible! ⬤Most collections come in up to four flavors:! ⬤basic (mostly = immutable)! ⬤immutable! ⬤mutable! ⬤parallel Clueda AG 20
Scala basic collection tree Clueda AG 21
Scala collections - immutable Clueda AG 22
Scala collections - mutable Clueda AG 23
Scala Collections Example : List (1 / 2) Clueda AG 24 val a = List("a","b","c")! // a: List[java.lang.String] = List(a, b, c)! val b = List(1,2,3)! //b: List[Int] = List(1, 2, 3)! ! a.head! // java.lang.String = a! a.tail! // List[java.lang.String] = List(b, c)! ! 0 :: b! // List[Int] = List(0, 1, 2, 3)! a ++ b! // List[Any] = List(a, b, c, 1, 2, 3)! a zip b! // List[(java.lang.String, Int)] = List((a,1), (b,2), (c,3))! a.sliding(2).toList! // List[List[String]] = List(List(a, b), List(b, c))!
Scala Collections : Map Clueda AG 25 val counting = Map(1 -> "eins", 2 -> "zwei", 3 -> "drei")! // counting: scala.collection.immutable.Map[Int,java.lang.String] =! // Map((1,eins), (2,zwei), (3,drei))! ! counting(2)! //java.lang.String = zwei! ! counting.get(2)! //Option[java.lang.String] = Some(zwei)! ! counting get 99! // Option[java.lang.String] = None!
Classes ⬤Classes are introduced by the keyword class ! ⬤Optionally each class has constructor elements in parentheses! ⬤optionally there is a class body! ⬤Things to look out for! ⬤Constructor elements prepended with the keyword val automatically get a getter method with the same name as the val (uniform access principle)! ⬤Constructor elements prepended with the keyword var get a getter method and a setter method with the same name as the var (uniform access principle)! ⬤Every expression within the body gets evaluated and called on object creation time Clueda AG 26
Example: A scala class ⬤Instances are created with new <ClassName> Clueda AG 27 class Document(val title: String, val author: String, yearInt: Int) {! ! val year = yearInt.toString! ! def shortCitation: String = author + " : " + title + ". " + year! }! ! val scalaBook = ! ! new Document("Programming In Scala","Martin Odersky",2011)! ! println(scalaBook.title)! println(scalaBook.year)!
Scala Objects ⬤Objects are created using the keyword object! ⬤They have NO constructor! ⬤Works roughly like a java class with static methods! ⬤Calling members ObjectName.member or ObjectName.method! ⬤Singleton-Object Clueda AG 28
Scala Object - Example Clueda AG 29 object DeepThought {! ! ! val theMeaningOfLife =! "The meaning of life: 42"! ! ! def speak {! println(theMeaningOfLife)! }! ! }! ! DeepThought.speak! //The meaning of life: 42
Companion Object ⬤Widely used pattern in Scala! ⬤A object with the same name as a class! ⬤Native Constructor Pattern Clueda AG 30
Case Class ⬤Introduce using the keywords case class! ⬤Like a „normal class“! ⬤Defines a companion object automatically with apply, unapply and some other methods! ⬤All constructor elements have getter methods as if prepended by val! ⬤Adds hashCode and equals based on the constructor Elements! ⬤Other classes must not inherit from case classes Clueda AG 31
Case Class - Example Clueda AG 32 case class Book(title: String, pages :Int)! //defined class Book! ! val book = Book("Necronomicon",1000)! //book: Book = Book(Necronomicon,1000)! ! println( book.title )! //Necronomicon! ! book == Book("Necronomicon",1000)! //Boolean = true! ! scala> book.hashCode! //-364191203! ! scala> Book("Necronomicon",1000).hashCode! //-364191203
Trait ⬤introduced with keyword trait! ⬤roughly comparable to a java interface! ⬤allows an effect resembling multiple inheritance without the dangers (i.e. diamond of death)! ⬤small building blocks! ⬤like ruby mixins Clueda AG 33
Trait - Example ⬤Two „traits“ are defined as Traits: Edible and ExoticTaste! ⬤Two classes are defined: Cake, which implements edible and ChiliChoc implements Edible and ExoticTaste Clueda AG 34 !! trait Edible {! ! def taste: String! ! def eat = println(taste)! }! ! trait ExoticTaste {! ! def eat: Unit! def describeTaste = {! ! ! eat! ! ! println("It tastes exotic")! ! }! }! !! case class Cake() extends Edible {! ! def taste = "sweet"! }! ! case class ChilliChoc(taste: String) ! ! ! ! ! ! ! extends Edible with ExoticTaste
Trait - Example : Usage Clueda AG 35 val cake = new Cake()! cake.eat! ! val chilliChoc = ChilliChoc("sweet and hot")! ! chilliChoc.eat! chilliChoc.describeTaste scala> val cake = new Cake()! cake: Cake = Cake()! ! scala> cake.eat! sweet! !! scala> val chilliChoc = ChilliChoc("sweet and hot")! chilliChoc: ChilliChoc = ChilliChoc(sweet and hot)! ! scala> chilliChoc.eat! sweet and hot! ! scala> chilliChoc.describeTaste! sweet and hot! It tastes exotic
control structures ⬤if, else! ⬤while! ⬤foreach, map! ⬤for-comprehensions Clueda AG 36
Control structures ⬤Control structures like while, if and else work as in Java or C! ⬤In contrast to Java, control structures are functions, i.e. they return a value! ⬤while always returns returns Unit Clueda AG 37 val x = if ( 1 < 2 ) true! //x: AnyVal = true
functional control structures ⬤some Examples! ⬤map : Apply function to each given element , keep result (like looping and collecting the results)! ! ! ⬤foreach: Apply function to each given element , drop result Clueda AG 38 List(1,2,3,4) map (x => x + 1)! //res1: List[Int] = List(2, 3, 4, 5) List(1,2,3) foreach ( x => println(s"And a $x") )! ! //And a 1! //And a 2! //And a 3
matching ⬤Pattern matching! ⬤keyword match! ⬤A group of cases introduced with the keyword case ! ⬤Switch on Steroids! ⬤Pattern Guards allow better control flow! ⬤Case Classes and Extractor Patterns for easy deconstruction and extraction of input Clueda AG 39
Matching Example Clueda AG 40 books: List[Any] = ! List(Book(Programming Scala,883,2012), Book(Programming Pearl,1104,2000), Book(Necronomicon, 666,666), Ein String, 5, 42)! !b ookComments: List[String] = ! List(New Scala Book by Martin Odersky from 2012, Programming Pearl 1104 2000, Necronomicon 666 666, Something else, Something else, an integer bigger than 10)! case class Book( title: String, pages: Int, year: Int)! ! val books = List( ! ! Book("Programming Scala", 883, 2012),! ! Book("Programming Pearl", 1104, 2000),! ! Book("Necronomicon",666,666),! ! "Ein String“, 5, 42! )! ! val bookComments = books map {! ! case Book("Programming Scala", pages, year) => ! ! ! s"New Scala Book by Martin Odersky from $year"! ! case Book(title, pages,year) => ! ! ! s"$title $pages $year"! ! case x: Int if x > 10 => ! ! ! "an integer bigger than 10"! ! case _ => ! ! ! "Something else"! }
For-Comprehensions ⬤program with a DSL that looks a lot like pseudocode! ⬤will be translated to map, filter, flatMap and reduce operations by the compiler Clueda AG 41 def isEven(x: Int) = x % 2 == 0! val integers = for {! x <- 1 to 99! if isEven(x)! if x % 5 == 0! } yield x! //integers: scala.collection.immutable.IndexedSeq[Int] = ! Vector(10, 20, 30, 40, 50, 60, 70, 80, 90) ~ Translated ~! (1 to 99) filter isEven filter ( _ % 5 == 0)
Some language features ⬤Strings: Interpolation and MultilineStrings! ⬤Option[Type]! ⬤Future[X]! ⬤XML erzeugen und bearbeiten! ⬤Reguläre Ausdrücke! ⬤Parallele Collections! ⬤Implicits Clueda AG 42
String Interpolation ⬤String concatenation works with „+“! ! ! ⬤String interpolation: prepending String with „s“ marking Variable with $! ! ! ⬤Complex Expressions are enclosed within ${ } Clueda AG 43 "hello" + " " + "world"! //res2: String = hello world val w = "world"! s"hello $w"! //res3: String = hello world val w = "world"! s"$w has length:${w.length}"! //res4: String = world has length:5!
String Concatenation/Interpolation - Example Clueda AG 44 val names = List("Roger","Felix", "Bene")! ! for (name <- names) println("Hello" + name)! ! //HelloRoger! //HelloFelix! //HelloBene val names = List("Roger","Felix", "Bene")! ! for (name <- names) println(s"Hello $name")! ! //Hello Roger! //Hello Felix! //Hello Bene
Multiline String ⬤Multiline String is created by using """ """ instead of " " ! ! ! ! ! ! ! ⬤allows embedding " in Strings and gets rid of double Escapes Clueda AG """This! | is a! | multiline String! | """! ! res6: String =! "This! is a! multiline String! " 45 """Hello "World"! """! //res12: String = "Hello "World"! "
Combined example Strings Clueda AG 46 val names = List("Roger","Felix", "Bene")! ! for (name <- names) println(! s"""Hello $name your name! has length:${ name.size }! and reads backwards as:"${ name.reverse}"! """! ) Hello Roger your name! has length:5! and reads backwards as:"regoR"! ! Hello Felix your name! has length:5! and reads backwards as:"xileF"! ! Hello Bene your name! has length:4! and reads backwards as:"eneB"
String format - The f interpolator ⬤prepend String with f ““! ⬤Syntax like C printf Clueda AG 47 def euroToDollar(euro: Double): Double = ! ! ! euro * 1.352065! ! val euro = List(1,2.5,5.12)! ! euro map euroToDollar foreach { d =>! println(f"Got $d%2.2f ($d)")! } Got 1,35 (1.352065)! Got 3,38 (3.3801625)! Got 6,92 (6.9225728)
The Option-Type ⬤Marks functions that may return a result but also may not return a result! ⬤Comes in two flavors: Some and None! ! ! ! ! ⬤like maybe in Haskell! ⬤A way to get around checking for null all the time Clueda AG 48 val x : Option[_] = None! //x: Option[_] = None! ! val x : Option[_] = Some("Hello World!")! //x: Option[_] = Some(Hello World!)
Option / List Comparison ⬤Option behaves like a list with one element! ! ! ⬤An empty Option is called None. None behaves like an empty list. Clueda AG 49 List( 1 ) map (i => i + 0.5 ) ! //List[Double] = List(1.5) Some( 1 ) map (i => i + 0.5 )! //Option[Double] = Some(1.5) val y : List[Int] = List()! //y: List[Int] = List()! ! y map (i => i+ 0.5)! //List[Double] = List() // Like an empty List! val x : Option[Int] = None ! //x: Option[Int] = None! x map (i => i+ 0.5)! // Option[Double] = None
Option-Type Beispiel: Option vs. null Clueda AG 50 val bigBangPHD = Map(! "Leonard" -> "Ph.D.",! "Sheldon" -> "Ph.D.,Sc.D",! "Rajesh" -> "Ph.D"! )! ! val friends = List("Leonard","Sheldon","Rajesh","Howard") bigBangPHD("Leonard")! //res0: java.lang.String = Ph.D.! ! bigBangPHD("Howard")! java.util.NoSuchElementException: key not found: Howard! ! at scala.collection.MapLike $class.default(MapLike.scala:223)! ! at scala.collection.immutable.Map $Map3.default(Map.scala:132) bigBangPHD get "Leonard"! //res1: Option[java.lang.String] ! = Some(Ph.D.)! ! bigBangPHD.get("Sheldon")! //res2: Option[java.lang.String] ! = Some(Ph.D., Sc.D)! ! bigBangPHD.get("Howard")! //res3: Option[java.lang.String] ! = None
Option -Type :Examples 1 ⬤Used widely throughout Scala! ⬤many builtin methods to handle Option Clueda AG 51 // Liste mit Options erzeugen ! friends map (bigBangPHD.get(_))! friends map bigBangPHD.get! //List[Option[java.lang.String]] = ! //List(Some(Ph.D.), Some(Ph.D.,Sc.D), Some(Ph.D), None)! !! // flatten entfernt None und „entpackt“ Some(thing)! friends map bigBangPHD.get flatten! friends flatMap (f => bigBangPHD.get(f))! /!/res5: List[java.lang.String] = List(Ph.D., Ph.D.,Sc.D, Ph.D)! // for comprehensions wenden Operationen nur auf Some() an und verwerfen None! for {! ! person <- friends! ! phd <- bigBangPHD get person! } yield s"$person has a $phd"! //List[java.lang.String] = ! //List(Leonard has a Ph.D., Sheldon has a Ph.D.,Sc.D, Rajesh has a Ph.D)
Option -Type : Examples 2‚ ⬤Option ist tief in Scala integriert! ⬤Es existieren viele Methoden die mit Option umgehen können // getOrElse erlaubt es einen Standardrückgabewert für None anzugeben, ansonsten wird Some(thing) „ausgepackt“! friends! ! .map( n =>(n,bigBangPHD.get(n)) ) // creates Tuple! ! .map{ case (n,d) => ! ! ! ! ! n + " " + d.getOrElse("Sheldon tells me you only have a master's degree.") ! ! }! //res7: List[java.lang.String] = ! //List(Leonard Ph.D.,! //Sheldon Ph.D.,Sc.D,! //Rajesh Ph.D,! //Howard Sheldon tells me you only have a master's degree.)! ! // Option Types besitzen Extraktoren für Pattern Matching! friends map bigBangPHD.get zip friends map {! Clueda AG 52 case (Some(phd), name ) => name + " : " + phd! case (None, name) => name + " is just an engineer"! }! ! //res10: List[java.lang.String] = List(Leonard : Ph.D.,! //Sheldon : Ph.D.,Sc.D,! //Rajesh : Ph.D,! //Howard is just an engineer)
Futures ⬤Are a way to abstract over asynchronous computation! ⬤non blocking! ⬤can be used much like Option! ⬤used in many popular Scala libraries Clueda AG 53
Futures - Plumbing ⬤Import com.scala.concurrent._ for future helpers! ⬤Every future needs an ExcecutionContext Clueda AG 54 import scala.concurrent._! import ExecutionContext.Implicits.global
Using Futures - Example val urls = ! List("http://www.clueda.de","http://www.neumann.biz","http://www.an-it.com")! ! def takeTime = { code to measure time }! def extractURLs(data: String) : Iterator[String] = …! def printURLs(data: String) : Unit = extractURLs(data) foreach println! def printLinks = urls map ( url => printURLs( getData(url) ) )! ! takeTime( printLinks )! takeTime( future { printLinks } )! Clueda AG 55 scala> takeTime( printLinks )! Url -> /favicon.gif! Url -> /stylesheets/refinery/style.css! Url -> /stylesheets/style.css?1380179036! …! res9: (String, List[Unit]) = ! ! (! ! ! took 2.109 s,! ! ! List((), (), ())! ! ) takeTime( future { printLinks } )! res10: (String, scala.concurrent.Future[List[Unit]]) = ! ! (! ! ! took 0.0 s,! ! ! scala.concurrent.impl.Promise$DefaultPromise@..! ! )! scala> Url -> /favicon.gif! Url -> /stylesheets/refinery/style.css! Url -> /stylesheets/style.css?1380179036! Url -> /stylesheets/flexslider.css?1349423712! …
Futures - Getting the result ⬤To get the result of a Future you have to block and wait! ! ! ⬤This is usually bad! ⬤Awaiting the result should happen as late as possible as it negates the benefits one gets using futures Clueda AG 56 import scala.concurrent.duration._! ! takeTime( Await.result( Future(printLinks), 10 seconds )) scala> takeTime( Await.result( Future(printLinks), 10 seconds )) warning: there were 1 feature warning(s); re-run with -feature for details Url -> /favicon.gif Url -> /stylesheets/refinery/style.css Url -> /stylesheets/style.css?1380179036 Url -> /stylesheets/flexslider.css?1349423712 … res30: (String, List[Unit]) = (took 1.976 s,List((), (), ()))
Futures - Composing ⬤As futures are Monads ( said it, done! ) they can be composed! ⬤The futures run asynchronously and will not wait for each other but await will wait till the last of the futures has completed or the timeout is reached. Clueda AG 57 def composedFutures: Future[(Unit,Unit,Unit)] = {! ! val f1 = Future( getAndPrintLinks("http://www.an-it.com") )! ! val f2 = Future( getAndPrintLinks("http://www.neumann.biz") )! ! val f3 = Future( getAndPrintLinks("http://www.clueda.com") )! ! ! for ( d1 <- f1 ; d2 <- f2 ; d3 <- f3) yield (d1,d2,d3)! } takeTime { Await.result(composedFutures,10 seconds) } warning: there were 1 feature warning(s); re-run with -feature for details Url -> /stylesheets/an-it.css?1339665275 Url -> mobile_stylesheets/mobile.css Url -> / Url -> ethnologie-studium res21: (String, (Unit, Unit, Unit)) = (took 0.834 s,((),(),()))
XML in Scala ⬤XML is a first class language citizen as string is in Java or Ruby! ⬤It’s possible to embed XML in Scala source code and get syntax highlighting Clueda AG 58
Scala - XML ⬤Xml can be written within scala sources! ⬤IDE s provide syntax-highlighting (Eclipse, Netbeans, IntelliJ)! ⬤Code can be embedded using { } within XML literals Clueda AG 59
Emit XML - Example Clueda AG 60 case class Book( title: String, pages: Int, year: Int) {! ! def toXML = ! <book>! <title>{title}</title>! <pages>{pages toString}</pages>! <year>{year toString}</year>! </book>! ! }! ! val books = List( ! Book("Programming Scala", 883, 2012),! Book("Programming Perl", 1104, 2000),! Book("Necronomicon",666,666) ! )! ! for ( book <- books) {! println(book.toXML)! }
Emitted XML Clueda AG 61 <book>! <title>Programming Scala</title>! <pages>883</pages>! <year>2012</year>! </book>! <book>! <title>Programming Perl</title>! <pages>1104</pages>! <year>2000</year>! </book>! <book>! <title>Necronomicon</title>! <pages>666</pages>! <year>666</year>! </book>!
Processing XML ⬤Scala provides an internal DSL influence providing a XPath like syntax ( instead of // and instead of / )! ⬤<xml></xml> "tag" : Shallow -Match! ⬤<xml></xml> "tag" : Deep -Match! ⬤<xml attribute=„wert“></xml> "@attribut" : Deep -Match on a XML attribute! ⬤(<xml></xml> "tag").text : Extracts the text value of an xml node Clueda AG 62
processing XML - Example Clueda AG 63 case class Book( title: String, pages: Int, year: Int) {! def toXML = ! <book>! <title>{title}</title>! <pages>{pages}</pages>! <year>{year}</year>! </book>! ! implicit def intToString(in : Int) : String = in.toString! }! ! object Book {! def fromXML(bookXML: scala.xml.NodeSeq) : Book= {! val title = (bookXML "title").text! val pages = (bookXML "pages").text.toInt! val year = (bookXML "year").text.toInt! new Book(title, pages, year)! }! }
processing XML - Result Clueda AG 64 val books = ! <books>! <book>! <title>Programming Scala</title>! <pages>883</pages>! <year>2012</year>! </book>! <book>! <title>Programming Perl</title>! <pages>1104</pages>! <year>2000</year>! </book>! <book>! <title>Necronomicon</title>! <pages>666</pages>! <year>666</year>! </book>! </books>! ! val booksInstances = (books „book") map Book.fromXML! val booksPages = (books "pages").map(_.text.toInt)! booksInstances: scala.collection.immutable.Seq[Book] = ! List(Book(Programming Scala,883,2012), Book(Programming Perl,1104,2000), Book(Necronomicon,666,666))! booksPages: scala.collection.immutable.Seq[Int] = List(883, 1104, 666)
Regular Expressions ⬤Creating a regular Expression:.r aus einem String erzeugen: ! ! ! ! ! ! ⬤Uses Java-Regex-Engine to create a NFA! ⬤Regex-Object also implement extractors for pattern matching Clueda AG 65 // Using the Constructor! new scala.util.matching.Regex("hrefs?=s?"([^"]+)"")! //Changing a string to a regex with the .r method! "hrefs?=s?"([^"]+)"".r! // Using """ , no need to escape " and double escaping of ! """hrefs?=s?"([^"]+)"""".r !
Regex - Usage Clueda AG 66 import scala.io.Source! ! val html = (Source fromURL "http://www.clueda.com").getLines mkString ""! ! val urlExtractor = """hrefs?=s?"([^"]+)"""".r! ! for ( urlExtractor(url) <- urlExtractor findAllIn html ) { ! ! println(s"Url -> $url")! }
first-order-functions / anonymous functions ⬤functions have a type like Integer or String! ⬤They can be arguments to function and passed around as values Clueda AG 67 val y = (x: Int) => x * x! //y: (Int) => Int = ! ! y apply 5! // Int = 25! ! y(5)! // Int = 25! ! val add = (x: Int, y: Int) => x + y! // add: (Int, Int) => Int = ! ! add(1,2)! // Int = 3
Implicits ⬤are introduced using the keyword implicit! ⬤trigger an automatic transformation! ⬤not stackable! ⬤shorter, more readable! ⬤may introduce „magic“! ⬤Pimp my library Pattern: Locally scopefied monkey patching Clueda AG 68
Implicits: Example ⬤no more need to manually transform year to string when using xml! ⬤will also work for all other integers in scope of Book Clueda AG 69 case class Book( title: String, pages: Int, year: Int) {! def toXML = ! <book>! <title>{title}</title>! <pages>{pages}</pages>! <year>{year}</year>! </book>! ! implicit def intToString(in : Int) : String = in.toString! }
Parallel Collections ⬤Asynchronous, parallel processing to take advantage of multicore processors! ⬤.par transforms a Collection to it’s parallel counterpart! ⬤.seq transforms a parallel Collection to a sequential one! ⬤Parallel is implemented as a trait => can be used to create own par collections! ⬤Also works for Map Clueda AG 70
Parallel Collections - Example // Sequential! (1 to 10) foreach println Clueda AG 71 // Parallel! (1 to 10).par foreach println
Parallele Collections - Examples II Clueda AG 72 scala> tenTimes foreach println! 10! 80! 90! 60! 30! 70! 100! 20! 40! 50 scala> tenTimes.seq foreach println! 10! 20! 30! 40! 50! 60! 70! 80! 90! 100 // Unordered! val tenTimes = (1 to 10).par map (_ * 10) ! tenTimes foreach println // Unordered! val tenTimes = (1 to 10).par map (_ * 10) ! tenTimes foreach println! ! //Ordered! //.seq transforms a parallel collection to a sequential one! tenTimes.seq foreach println
Build your own control structures ⬤Curried functions can be used to build control structures Clueda AG 73 object ControlStructures {! def unless( test: => Boolean)(action: => Any) = ! if (! test) action! ! def times( n: Int )(action: => Unit) {! (1 to n) foreach { _ => action}! }! } scala> import ControlStructures._! /!/import ControlStructures._! scala> times(2) { println("Hoorray :)")}! Hoorray :)! H!oorray :)! scala> unless (5 < 10) { println("Math stopped working.") }! /!/ Any = ()! scala> val ifNot = unless (2 + 2 != 4) { "Math still works." }! // Any = Math still works.!
Scala - Patterns ⬤Structural Typing! ⬤Pimp-My-Library-Pattern Clueda AG 74
Structural Typing ⬤Classed are described by methods and return types they provide! ⬤Works like duck typing but the checking happens in compile time, not run time Clueda AG 75 class Cowboy { def shout = "Yehaaw !" }! class Pirate { def shout = "Arrrgh !" }! ! def sayHelloTo( person : { def shout: String} ) = ! ! s"Me : Hello!n $person shouts ${person.shout}" val johnWayne = new Cowboy! ! sayHelloTo(johnWayne)! scala> sayHelloTo(johnWayne)! res4: String =! Me : Hello!! Cowboy@185f8f75 shouts Yehaaw ! val guybrush = new Pirate! ! sayHelloTo(guybrush)! scala> sayHelloTo(guybrush)! res5: String =! Me : Hello!! Pirate@29c356d3 shouts Arrrgh !
Pimp-My-Library-Pattern ⬤Add new functions to existing libraries without changing the code! ⬤Like monkey patching! ⬤type safe! ⬤scoped Clueda AG 76
Pimp-My-Library-Pattern : Example Source Clueda AG 77 object PimpString {! ! class WeatherString(s: String) {! def ☀ = { println(s"$s sunny!") }! def ☁ = "Dont't forget your ☂!“! }! ! implicit class ♔(name : String) {! def hail = s"Hail to king $name"! }! ! implicit def pimpString(in: String) : WeatherString = ! !new WeatherString(in)! }!
Pimp-My-Library-Pattern : Example Usage Clueda AG ⬤Use with caution ! scala> import PimpString._! import PimpString._! ! scala> "Monday is" ☀! Monday is sunny!! ! scala> "???".☁! res8: String = Dont't forget your ☂ scala> val anotherKing = ♔("Louis")! anotherKing: PimpString.♔ = PimpString$$u2654@12359094! ! scala> val aKing = implicitly[♔]("George")! aKing: PimpString.♔ = PimpString$$u2654@5081371! ! scala> aKing.hail! res10: String = Hail to king George 78 scala> val guys = List("James", "Louis", "Franz-Ferdinand")! guys: List[String] = List(James, Louis, Franz-Ferdinand)! ! scala> guys map (_.hail)! res13: List[String] = List(Hail to king James, Hail to king Louis, Hail to king Franz- Ferdinand)
Scala - imperative, object oriented, functional Clueda AG 79
Scala -imperative, object oriented, functional - Rules of the thumb ⬤functional if possible! ⬤Sometimes imperative is better and faster ! ⬤start out with val and immutable collections,switch to var or mutable collections if needed! ⬤Use object orientation to encapsulate side effects and imperative code Clueda AG 80
Advantage of the functional approach ⬤short! ⬤no side effects -> easier to reason about! ⬤composeable Clueda AG 81
Advantage of the imperative approach ⬤familiar! ⬤Eventually everything will be iterative after being translated to machine code Clueda AG 82
Imperative vs. functional, Examples var i = 0! while (i < args.length) {! if ( i != 0 )! print(" ")! print( args(i) )! i += 1! }! println() Clueda AG 83 Imperative Functional var x = 1! var sum = 0! while (x <= 9999) {! sum += x! x += 1! }! (1 to 9999) foldLeft(0)(_ + _) (1 to 9999) sum println( args mkString " " ) println( ! args reduceOption ( (acc,arg ) => ! acc + " " + arg! )! )
Imperative vs. functional, Examples 2 Clueda AG 84 Imperative Functional var i = null! var data = gettingData()! ! if (data != null && data.size > 0) ! ! i = data(0)! else ! ! i = 42! val i = ! ! if (data != null && data.size > 0)! ! ! data(0)! ! else! ! ! 42 val i = ! ! gettingData().headOption getOrElse 42
Literatur: ⬤Wampler, D., & Payne, A. (2009). Programming Scala. Sebastopol, CA: O'Reilly.! ⬤Odersky, M., Spoon, L., & Venners, B. (2008). Programming in Scala. Mountain View, Calif: Artima.! ⬤Malayeri, M. “Pimp My Library” Is An Affront To Pimpers Of The World, Everywhere! ⬤http://www.scala-lang.org! ⬤http://www.an-it.com Clueda AG 85
Thanks for participating :) Clueda AG 86

Scala Workshop

  • 1.
    An Introduction toScala Andreas Neumann, Senior Software Engineer! a.neumann@clueda.com
  • 2.
    Overview ⬤A veryshort history of Scala! ⬤Using Scala - Basics: Compile and run! ⬤Introduction to the core concepts : vals, classes, objects, traits, control structures and functions! ⬤Some intermediate concepts in Scala: Pattern Matching, Option, XML, Futures! ⬤Patterns in Scala! ⬤Functional Style Clueda AG 2
  • 3.
    About Scala ⬤AJVM Languge! ⬤multiparadigmatic! ⬤functional object orientated Clueda AG 3
  • 4.
    The father ofScala - Martin Odersky ⬤Professor EPFL! ⬤Java-Compiler! ⬤Java 1.4 Generics! ⬤PIZZA! ⬤Scala! ⬤Co-Founder Typesafe Clueda AG 4
  • 5.
    The company behindScala - ⬤Training! ⬤Consulting! ⬤Scala! ⬤Actor! ⬤Play Clueda AG 5
  • 6.
    Who is usingScala ⬤Xerox! ⬤Twitter! ⬤Foursquare! ⬤Sony! ⬤Siemens! ⬤clueda! ⬤… Clueda AG 6
  • 7.
    Nice features ⬤Canbe integrated in any Java based architecture! ⬤support concurrent and asynchronous operations out of the box in many flavors (Futures,Parallel Collections, Akka)! ⬤great for embedded DSLs Clueda AG 7
  • 8.
    Introduction ⬤Run code/ compile Code! ⬤Syntax (some tips)! ⬤declare variables! ⬤functions! ⬤clases, traits and objects Clueda AG 8
  • 9.
    Run code, compilesources ⬤Scala can be used in many different environments:! ⬤compile and run on a JVM! ⬤run as a script! ⬤in an interactive console, called REPL Clueda AG 9
  • 10.
    Scala - compiler/ scalac ⬤the compiler is called scalac! ⬤The sources are compiled to Java byte code! ⬤*.class! ⬤run class with scala <name> Clueda AG 10
  • 11.
    Scripting with Scala- Unix ⬤Scala can be used as scripting language! ⬤change mode to executeable or run by bash Clueda AG 11 #!/bin/sh exec scala "$0" "$@" !# ! object HelloWorld { def main(args: Array[String]) { println("Hello, world! " + args.toList) } } HelloWorld.main(args)
  • 12.
    Scripting with Scala- Windows ⬤Resembles UNIX use a batch script instead! ⬤*.bat! ⬤run Clueda AG 12 ::#!! @echo off! call scala %0 %*! goto :eof! ::!#! ! object HelloWorld {! def main(args: Array[String]) {! println("Hello, world! " +! args.toList)! }! }! ! HelloWorld.main(args)
  • 13.
    Scala - Interpreter/ REPL ⬤part of the scala installation! ⬤Start by typing scala the shell! ⬤:q or CTRL + d to quit Clueda AG 13 neumann@mac ~> scala! !! Welcome to Scala version 2.11.1 (Java HotSpot(TM) ! 64-Bit Server VM, Java 1.7.0_55).! Type in expressions to have them evaluated.! Type :help for more information.! ! scala> println("Hello World")! Hello World! ! scala> :q! !! neumann@mac ~>
  • 14.
  • 15.
    Syntax ⬤No needfor „;“ , one expression per line ! ⬤Still possible to add ; if for example you want several expression within one line! ⬤The dot on method invocations can be dropped. It is best practice to do so with infix invocation but not with postfix operations. Clueda AG 15 "Hallo Welt !".split(" ")! //res0: Array[String] = Array(Hallo, Welt, !)! ! scala> "Hallo Welt !" split " " ! //res2: Array[String] = Array(Hallo, Welt, !) scala> List(1,2.3).map(_ * 3).head! //res3: Double = 3.0! ! scala> ( List(1,2.3) map (_ * 3) ).head! //res4: Double = 3.0
  • 16.
    val, vars ⬤valcreates a Value which is not changeable ( like final modifier in Java)! ⬤var creates a Variable , which can be reassigned different values Clueda AG 16
  • 17.
    Example: val andvar Clueda AG 17 val x = 42! //x: Int = 42! ! var y = 99! //y: Int = 99! ! y = 1! y: Int = 1! ! x = 1! error: reassignment to val! x = 1! ^
  • 18.
    Types and typeinferrence ⬤Types are introduced after : which is written behind the var/val! ! ⬤Giving the type explicitly is optional as the type inference can infer the type. It’s considered good style to add the type information nonetheless. Clueda AG 18 s : String = "ein String" val a = "Hallo"! //a: java.lang.String = Hallo! ! val b = 1! //b: Int = 1! ! val c = 3.5! //c: Double = 3.5! ! val d = List(1,2.0)! //d: List[Double] = List(1.0, 2.0)
  • 19.
    define methods ⬤methodsare introduced with def! ⬤optionally there can be a list of parameters enclosed by parentheses! ⬤then the body of the function! ⬤methods returning a value put a between name arguments and the body! ⬤the result of the last expression evaluated within the body is the return value Clueda AG 19 def write(aString: String):Unit= {! println(aString) ! }! ! write("Hallo ihr alle da draußen!")! //Hallo ihr alle da draußen! def add(x: Int, y:Int) : Int = { ! x + y! }! ! add(40,2)! //res0: Int = 42
  • 20.
    Collections ⬤Scala hasa big Collections library! ⬤Collections provide similar interfaces as far as possible! ⬤Most collections come in up to four flavors:! ⬤basic (mostly = immutable)! ⬤immutable! ⬤mutable! ⬤parallel Clueda AG 20
  • 21.
    Scala basic collectiontree Clueda AG 21
  • 22.
    Scala collections -immutable Clueda AG 22
  • 23.
    Scala collections -mutable Clueda AG 23
  • 24.
    Scala Collections Example: List (1 / 2) Clueda AG 24 val a = List("a","b","c")! // a: List[java.lang.String] = List(a, b, c)! val b = List(1,2,3)! //b: List[Int] = List(1, 2, 3)! ! a.head! // java.lang.String = a! a.tail! // List[java.lang.String] = List(b, c)! ! 0 :: b! // List[Int] = List(0, 1, 2, 3)! a ++ b! // List[Any] = List(a, b, c, 1, 2, 3)! a zip b! // List[(java.lang.String, Int)] = List((a,1), (b,2), (c,3))! a.sliding(2).toList! // List[List[String]] = List(List(a, b), List(b, c))!
  • 25.
    Scala Collections :Map Clueda AG 25 val counting = Map(1 -> "eins", 2 -> "zwei", 3 -> "drei")! // counting: scala.collection.immutable.Map[Int,java.lang.String] =! // Map((1,eins), (2,zwei), (3,drei))! ! counting(2)! //java.lang.String = zwei! ! counting.get(2)! //Option[java.lang.String] = Some(zwei)! ! counting get 99! // Option[java.lang.String] = None!
  • 26.
    Classes ⬤Classes areintroduced by the keyword class ! ⬤Optionally each class has constructor elements in parentheses! ⬤optionally there is a class body! ⬤Things to look out for! ⬤Constructor elements prepended with the keyword val automatically get a getter method with the same name as the val (uniform access principle)! ⬤Constructor elements prepended with the keyword var get a getter method and a setter method with the same name as the var (uniform access principle)! ⬤Every expression within the body gets evaluated and called on object creation time Clueda AG 26
  • 27.
    Example: A scalaclass ⬤Instances are created with new <ClassName> Clueda AG 27 class Document(val title: String, val author: String, yearInt: Int) {! ! val year = yearInt.toString! ! def shortCitation: String = author + " : " + title + ". " + year! }! ! val scalaBook = ! ! new Document("Programming In Scala","Martin Odersky",2011)! ! println(scalaBook.title)! println(scalaBook.year)!
  • 28.
    Scala Objects ⬤Objectsare created using the keyword object! ⬤They have NO constructor! ⬤Works roughly like a java class with static methods! ⬤Calling members ObjectName.member or ObjectName.method! ⬤Singleton-Object Clueda AG 28
  • 29.
    Scala Object -Example Clueda AG 29 object DeepThought {! ! ! val theMeaningOfLife =! "The meaning of life: 42"! ! ! def speak {! println(theMeaningOfLife)! }! ! }! ! DeepThought.speak! //The meaning of life: 42
  • 30.
    Companion Object ⬤Widelyused pattern in Scala! ⬤A object with the same name as a class! ⬤Native Constructor Pattern Clueda AG 30
  • 31.
    Case Class ⬤Introduceusing the keywords case class! ⬤Like a „normal class“! ⬤Defines a companion object automatically with apply, unapply and some other methods! ⬤All constructor elements have getter methods as if prepended by val! ⬤Adds hashCode and equals based on the constructor Elements! ⬤Other classes must not inherit from case classes Clueda AG 31
  • 32.
    Case Class -Example Clueda AG 32 case class Book(title: String, pages :Int)! //defined class Book! ! val book = Book("Necronomicon",1000)! //book: Book = Book(Necronomicon,1000)! ! println( book.title )! //Necronomicon! ! book == Book("Necronomicon",1000)! //Boolean = true! ! scala> book.hashCode! //-364191203! ! scala> Book("Necronomicon",1000).hashCode! //-364191203
  • 33.
    Trait ⬤introduced withkeyword trait! ⬤roughly comparable to a java interface! ⬤allows an effect resembling multiple inheritance without the dangers (i.e. diamond of death)! ⬤small building blocks! ⬤like ruby mixins Clueda AG 33
  • 34.
    Trait - Example ⬤Two „traits“ are defined as Traits: Edible and ExoticTaste! ⬤Two classes are defined: Cake, which implements edible and ChiliChoc implements Edible and ExoticTaste Clueda AG 34 !! trait Edible {! ! def taste: String! ! def eat = println(taste)! }! ! trait ExoticTaste {! ! def eat: Unit! def describeTaste = {! ! ! eat! ! ! println("It tastes exotic")! ! }! }! !! case class Cake() extends Edible {! ! def taste = "sweet"! }! ! case class ChilliChoc(taste: String) ! ! ! ! ! ! ! extends Edible with ExoticTaste
  • 35.
    Trait - Example: Usage Clueda AG 35 val cake = new Cake()! cake.eat! ! val chilliChoc = ChilliChoc("sweet and hot")! ! chilliChoc.eat! chilliChoc.describeTaste scala> val cake = new Cake()! cake: Cake = Cake()! ! scala> cake.eat! sweet! !! scala> val chilliChoc = ChilliChoc("sweet and hot")! chilliChoc: ChilliChoc = ChilliChoc(sweet and hot)! ! scala> chilliChoc.eat! sweet and hot! ! scala> chilliChoc.describeTaste! sweet and hot! It tastes exotic
  • 36.
    control structures ⬤if,else! ⬤while! ⬤foreach, map! ⬤for-comprehensions Clueda AG 36
  • 37.
    Control structures ⬤Controlstructures like while, if and else work as in Java or C! ⬤In contrast to Java, control structures are functions, i.e. they return a value! ⬤while always returns returns Unit Clueda AG 37 val x = if ( 1 < 2 ) true! //x: AnyVal = true
  • 38.
    functional control structures ⬤some Examples! ⬤map : Apply function to each given element , keep result (like looping and collecting the results)! ! ! ⬤foreach: Apply function to each given element , drop result Clueda AG 38 List(1,2,3,4) map (x => x + 1)! //res1: List[Int] = List(2, 3, 4, 5) List(1,2,3) foreach ( x => println(s"And a $x") )! ! //And a 1! //And a 2! //And a 3
  • 39.
    matching ⬤Pattern matching! ⬤keyword match! ⬤A group of cases introduced with the keyword case ! ⬤Switch on Steroids! ⬤Pattern Guards allow better control flow! ⬤Case Classes and Extractor Patterns for easy deconstruction and extraction of input Clueda AG 39
  • 40.
    Matching Example CluedaAG 40 books: List[Any] = ! List(Book(Programming Scala,883,2012), Book(Programming Pearl,1104,2000), Book(Necronomicon, 666,666), Ein String, 5, 42)! !b ookComments: List[String] = ! List(New Scala Book by Martin Odersky from 2012, Programming Pearl 1104 2000, Necronomicon 666 666, Something else, Something else, an integer bigger than 10)! case class Book( title: String, pages: Int, year: Int)! ! val books = List( ! ! Book("Programming Scala", 883, 2012),! ! Book("Programming Pearl", 1104, 2000),! ! Book("Necronomicon",666,666),! ! "Ein String“, 5, 42! )! ! val bookComments = books map {! ! case Book("Programming Scala", pages, year) => ! ! ! s"New Scala Book by Martin Odersky from $year"! ! case Book(title, pages,year) => ! ! ! s"$title $pages $year"! ! case x: Int if x > 10 => ! ! ! "an integer bigger than 10"! ! case _ => ! ! ! "Something else"! }
  • 41.
    For-Comprehensions ⬤program witha DSL that looks a lot like pseudocode! ⬤will be translated to map, filter, flatMap and reduce operations by the compiler Clueda AG 41 def isEven(x: Int) = x % 2 == 0! val integers = for {! x <- 1 to 99! if isEven(x)! if x % 5 == 0! } yield x! //integers: scala.collection.immutable.IndexedSeq[Int] = ! Vector(10, 20, 30, 40, 50, 60, 70, 80, 90) ~ Translated ~! (1 to 99) filter isEven filter ( _ % 5 == 0)
  • 42.
    Some language features ⬤Strings: Interpolation and MultilineStrings! ⬤Option[Type]! ⬤Future[X]! ⬤XML erzeugen und bearbeiten! ⬤Reguläre Ausdrücke! ⬤Parallele Collections! ⬤Implicits Clueda AG 42
  • 43.
    String Interpolation ⬤Stringconcatenation works with „+“! ! ! ⬤String interpolation: prepending String with „s“ marking Variable with $! ! ! ⬤Complex Expressions are enclosed within ${ } Clueda AG 43 "hello" + " " + "world"! //res2: String = hello world val w = "world"! s"hello $w"! //res3: String = hello world val w = "world"! s"$w has length:${w.length}"! //res4: String = world has length:5!
  • 44.
    String Concatenation/Interpolation -Example Clueda AG 44 val names = List("Roger","Felix", "Bene")! ! for (name <- names) println("Hello" + name)! ! //HelloRoger! //HelloFelix! //HelloBene val names = List("Roger","Felix", "Bene")! ! for (name <- names) println(s"Hello $name")! ! //Hello Roger! //Hello Felix! //Hello Bene
  • 45.
    Multiline String ⬤MultilineString is created by using """ """ instead of " " ! ! ! ! ! ! ! ⬤allows embedding " in Strings and gets rid of double Escapes Clueda AG """This! | is a! | multiline String! | """! ! res6: String =! "This! is a! multiline String! " 45 """Hello "World"! """! //res12: String = "Hello "World"! "
  • 46.
    Combined example Strings Clueda AG 46 val names = List("Roger","Felix", "Bene")! ! for (name <- names) println(! s"""Hello $name your name! has length:${ name.size }! and reads backwards as:"${ name.reverse}"! """! ) Hello Roger your name! has length:5! and reads backwards as:"regoR"! ! Hello Felix your name! has length:5! and reads backwards as:"xileF"! ! Hello Bene your name! has length:4! and reads backwards as:"eneB"
  • 47.
    String format -The f interpolator ⬤prepend String with f ““! ⬤Syntax like C printf Clueda AG 47 def euroToDollar(euro: Double): Double = ! ! ! euro * 1.352065! ! val euro = List(1,2.5,5.12)! ! euro map euroToDollar foreach { d =>! println(f"Got $d%2.2f ($d)")! } Got 1,35 (1.352065)! Got 3,38 (3.3801625)! Got 6,92 (6.9225728)
  • 48.
    The Option-Type ⬤Marksfunctions that may return a result but also may not return a result! ⬤Comes in two flavors: Some and None! ! ! ! ! ⬤like maybe in Haskell! ⬤A way to get around checking for null all the time Clueda AG 48 val x : Option[_] = None! //x: Option[_] = None! ! val x : Option[_] = Some("Hello World!")! //x: Option[_] = Some(Hello World!)
  • 49.
    Option / ListComparison ⬤Option behaves like a list with one element! ! ! ⬤An empty Option is called None. None behaves like an empty list. Clueda AG 49 List( 1 ) map (i => i + 0.5 ) ! //List[Double] = List(1.5) Some( 1 ) map (i => i + 0.5 )! //Option[Double] = Some(1.5) val y : List[Int] = List()! //y: List[Int] = List()! ! y map (i => i+ 0.5)! //List[Double] = List() // Like an empty List! val x : Option[Int] = None ! //x: Option[Int] = None! x map (i => i+ 0.5)! // Option[Double] = None
  • 50.
    Option-Type Beispiel: Optionvs. null Clueda AG 50 val bigBangPHD = Map(! "Leonard" -> "Ph.D.",! "Sheldon" -> "Ph.D.,Sc.D",! "Rajesh" -> "Ph.D"! )! ! val friends = List("Leonard","Sheldon","Rajesh","Howard") bigBangPHD("Leonard")! //res0: java.lang.String = Ph.D.! ! bigBangPHD("Howard")! java.util.NoSuchElementException: key not found: Howard! ! at scala.collection.MapLike $class.default(MapLike.scala:223)! ! at scala.collection.immutable.Map $Map3.default(Map.scala:132) bigBangPHD get "Leonard"! //res1: Option[java.lang.String] ! = Some(Ph.D.)! ! bigBangPHD.get("Sheldon")! //res2: Option[java.lang.String] ! = Some(Ph.D., Sc.D)! ! bigBangPHD.get("Howard")! //res3: Option[java.lang.String] ! = None
  • 51.
    Option -Type :Examples1 ⬤Used widely throughout Scala! ⬤many builtin methods to handle Option Clueda AG 51 // Liste mit Options erzeugen ! friends map (bigBangPHD.get(_))! friends map bigBangPHD.get! //List[Option[java.lang.String]] = ! //List(Some(Ph.D.), Some(Ph.D.,Sc.D), Some(Ph.D), None)! !! // flatten entfernt None und „entpackt“ Some(thing)! friends map bigBangPHD.get flatten! friends flatMap (f => bigBangPHD.get(f))! /!/res5: List[java.lang.String] = List(Ph.D., Ph.D.,Sc.D, Ph.D)! // for comprehensions wenden Operationen nur auf Some() an und verwerfen None! for {! ! person <- friends! ! phd <- bigBangPHD get person! } yield s"$person has a $phd"! //List[java.lang.String] = ! //List(Leonard has a Ph.D., Sheldon has a Ph.D.,Sc.D, Rajesh has a Ph.D)
  • 52.
    Option -Type :Examples 2‚ ⬤Option ist tief in Scala integriert! ⬤Es existieren viele Methoden die mit Option umgehen können // getOrElse erlaubt es einen Standardrückgabewert für None anzugeben, ansonsten wird Some(thing) „ausgepackt“! friends! ! .map( n =>(n,bigBangPHD.get(n)) ) // creates Tuple! ! .map{ case (n,d) => ! ! ! ! ! n + " " + d.getOrElse("Sheldon tells me you only have a master's degree.") ! ! }! //res7: List[java.lang.String] = ! //List(Leonard Ph.D.,! //Sheldon Ph.D.,Sc.D,! //Rajesh Ph.D,! //Howard Sheldon tells me you only have a master's degree.)! ! // Option Types besitzen Extraktoren für Pattern Matching! friends map bigBangPHD.get zip friends map {! Clueda AG 52 case (Some(phd), name ) => name + " : " + phd! case (None, name) => name + " is just an engineer"! }! ! //res10: List[java.lang.String] = List(Leonard : Ph.D.,! //Sheldon : Ph.D.,Sc.D,! //Rajesh : Ph.D,! //Howard is just an engineer)
  • 53.
    Futures ⬤Are away to abstract over asynchronous computation! ⬤non blocking! ⬤can be used much like Option! ⬤used in many popular Scala libraries Clueda AG 53
  • 54.
    Futures - Plumbing ⬤Import com.scala.concurrent._ for future helpers! ⬤Every future needs an ExcecutionContext Clueda AG 54 import scala.concurrent._! import ExecutionContext.Implicits.global
  • 55.
    Using Futures -Example val urls = ! List("http://www.clueda.de","http://www.neumann.biz","http://www.an-it.com")! ! def takeTime = { code to measure time }! def extractURLs(data: String) : Iterator[String] = …! def printURLs(data: String) : Unit = extractURLs(data) foreach println! def printLinks = urls map ( url => printURLs( getData(url) ) )! ! takeTime( printLinks )! takeTime( future { printLinks } )! Clueda AG 55 scala> takeTime( printLinks )! Url -> /favicon.gif! Url -> /stylesheets/refinery/style.css! Url -> /stylesheets/style.css?1380179036! …! res9: (String, List[Unit]) = ! ! (! ! ! took 2.109 s,! ! ! List((), (), ())! ! ) takeTime( future { printLinks } )! res10: (String, scala.concurrent.Future[List[Unit]]) = ! ! (! ! ! took 0.0 s,! ! ! scala.concurrent.impl.Promise$DefaultPromise@..! ! )! scala> Url -> /favicon.gif! Url -> /stylesheets/refinery/style.css! Url -> /stylesheets/style.css?1380179036! Url -> /stylesheets/flexslider.css?1349423712! …
  • 56.
    Futures - Gettingthe result ⬤To get the result of a Future you have to block and wait! ! ! ⬤This is usually bad! ⬤Awaiting the result should happen as late as possible as it negates the benefits one gets using futures Clueda AG 56 import scala.concurrent.duration._! ! takeTime( Await.result( Future(printLinks), 10 seconds )) scala> takeTime( Await.result( Future(printLinks), 10 seconds )) warning: there were 1 feature warning(s); re-run with -feature for details Url -> /favicon.gif Url -> /stylesheets/refinery/style.css Url -> /stylesheets/style.css?1380179036 Url -> /stylesheets/flexslider.css?1349423712 … res30: (String, List[Unit]) = (took 1.976 s,List((), (), ()))
  • 57.
    Futures - Composing ⬤As futures are Monads ( said it, done! ) they can be composed! ⬤The futures run asynchronously and will not wait for each other but await will wait till the last of the futures has completed or the timeout is reached. Clueda AG 57 def composedFutures: Future[(Unit,Unit,Unit)] = {! ! val f1 = Future( getAndPrintLinks("http://www.an-it.com") )! ! val f2 = Future( getAndPrintLinks("http://www.neumann.biz") )! ! val f3 = Future( getAndPrintLinks("http://www.clueda.com") )! ! ! for ( d1 <- f1 ; d2 <- f2 ; d3 <- f3) yield (d1,d2,d3)! } takeTime { Await.result(composedFutures,10 seconds) } warning: there were 1 feature warning(s); re-run with -feature for details Url -> /stylesheets/an-it.css?1339665275 Url -> mobile_stylesheets/mobile.css Url -> / Url -> ethnologie-studium res21: (String, (Unit, Unit, Unit)) = (took 0.834 s,((),(),()))
  • 58.
    XML in Scala ⬤XML is a first class language citizen as string is in Java or Ruby! ⬤It’s possible to embed XML in Scala source code and get syntax highlighting Clueda AG 58
  • 59.
    Scala - XML ⬤Xml can be written within scala sources! ⬤IDE s provide syntax-highlighting (Eclipse, Netbeans, IntelliJ)! ⬤Code can be embedded using { } within XML literals Clueda AG 59
  • 60.
    Emit XML -Example Clueda AG 60 case class Book( title: String, pages: Int, year: Int) {! ! def toXML = ! <book>! <title>{title}</title>! <pages>{pages toString}</pages>! <year>{year toString}</year>! </book>! ! }! ! val books = List( ! Book("Programming Scala", 883, 2012),! Book("Programming Perl", 1104, 2000),! Book("Necronomicon",666,666) ! )! ! for ( book <- books) {! println(book.toXML)! }
  • 61.
    Emitted XML CluedaAG 61 <book>! <title>Programming Scala</title>! <pages>883</pages>! <year>2012</year>! </book>! <book>! <title>Programming Perl</title>! <pages>1104</pages>! <year>2000</year>! </book>! <book>! <title>Necronomicon</title>! <pages>666</pages>! <year>666</year>! </book>!
  • 62.
    Processing XML ⬤Scalaprovides an internal DSL influence providing a XPath like syntax ( instead of // and instead of / )! ⬤<xml></xml> "tag" : Shallow -Match! ⬤<xml></xml> "tag" : Deep -Match! ⬤<xml attribute=„wert“></xml> "@attribut" : Deep -Match on a XML attribute! ⬤(<xml></xml> "tag").text : Extracts the text value of an xml node Clueda AG 62
  • 63.
    processing XML -Example Clueda AG 63 case class Book( title: String, pages: Int, year: Int) {! def toXML = ! <book>! <title>{title}</title>! <pages>{pages}</pages>! <year>{year}</year>! </book>! ! implicit def intToString(in : Int) : String = in.toString! }! ! object Book {! def fromXML(bookXML: scala.xml.NodeSeq) : Book= {! val title = (bookXML "title").text! val pages = (bookXML "pages").text.toInt! val year = (bookXML "year").text.toInt! new Book(title, pages, year)! }! }
  • 64.
    processing XML -Result Clueda AG 64 val books = ! <books>! <book>! <title>Programming Scala</title>! <pages>883</pages>! <year>2012</year>! </book>! <book>! <title>Programming Perl</title>! <pages>1104</pages>! <year>2000</year>! </book>! <book>! <title>Necronomicon</title>! <pages>666</pages>! <year>666</year>! </book>! </books>! ! val booksInstances = (books „book") map Book.fromXML! val booksPages = (books "pages").map(_.text.toInt)! booksInstances: scala.collection.immutable.Seq[Book] = ! List(Book(Programming Scala,883,2012), Book(Programming Perl,1104,2000), Book(Necronomicon,666,666))! booksPages: scala.collection.immutable.Seq[Int] = List(883, 1104, 666)
  • 65.
    Regular Expressions ⬤Creatinga regular Expression:.r aus einem String erzeugen: ! ! ! ! ! ! ⬤Uses Java-Regex-Engine to create a NFA! ⬤Regex-Object also implement extractors for pattern matching Clueda AG 65 // Using the Constructor! new scala.util.matching.Regex("hrefs?=s?"([^"]+)"")! //Changing a string to a regex with the .r method! "hrefs?=s?"([^"]+)"".r! // Using """ , no need to escape " and double escaping of ! """hrefs?=s?"([^"]+)"""".r !
  • 66.
    Regex - Usage Clueda AG 66 import scala.io.Source! ! val html = (Source fromURL "http://www.clueda.com").getLines mkString ""! ! val urlExtractor = """hrefs?=s?"([^"]+)"""".r! ! for ( urlExtractor(url) <- urlExtractor findAllIn html ) { ! ! println(s"Url -> $url")! }
  • 67.
    first-order-functions / anonymousfunctions ⬤functions have a type like Integer or String! ⬤They can be arguments to function and passed around as values Clueda AG 67 val y = (x: Int) => x * x! //y: (Int) => Int = ! ! y apply 5! // Int = 25! ! y(5)! // Int = 25! ! val add = (x: Int, y: Int) => x + y! // add: (Int, Int) => Int = ! ! add(1,2)! // Int = 3
  • 68.
    Implicits ⬤are introducedusing the keyword implicit! ⬤trigger an automatic transformation! ⬤not stackable! ⬤shorter, more readable! ⬤may introduce „magic“! ⬤Pimp my library Pattern: Locally scopefied monkey patching Clueda AG 68
  • 69.
    Implicits: Example ⬤nomore need to manually transform year to string when using xml! ⬤will also work for all other integers in scope of Book Clueda AG 69 case class Book( title: String, pages: Int, year: Int) {! def toXML = ! <book>! <title>{title}</title>! <pages>{pages}</pages>! <year>{year}</year>! </book>! ! implicit def intToString(in : Int) : String = in.toString! }
  • 70.
    Parallel Collections ⬤Asynchronous,parallel processing to take advantage of multicore processors! ⬤.par transforms a Collection to it’s parallel counterpart! ⬤.seq transforms a parallel Collection to a sequential one! ⬤Parallel is implemented as a trait => can be used to create own par collections! ⬤Also works for Map Clueda AG 70
  • 71.
    Parallel Collections -Example // Sequential! (1 to 10) foreach println Clueda AG 71 // Parallel! (1 to 10).par foreach println
  • 72.
    Parallele Collections -Examples II Clueda AG 72 scala> tenTimes foreach println! 10! 80! 90! 60! 30! 70! 100! 20! 40! 50 scala> tenTimes.seq foreach println! 10! 20! 30! 40! 50! 60! 70! 80! 90! 100 // Unordered! val tenTimes = (1 to 10).par map (_ * 10) ! tenTimes foreach println // Unordered! val tenTimes = (1 to 10).par map (_ * 10) ! tenTimes foreach println! ! //Ordered! //.seq transforms a parallel collection to a sequential one! tenTimes.seq foreach println
  • 73.
    Build your owncontrol structures ⬤Curried functions can be used to build control structures Clueda AG 73 object ControlStructures {! def unless( test: => Boolean)(action: => Any) = ! if (! test) action! ! def times( n: Int )(action: => Unit) {! (1 to n) foreach { _ => action}! }! } scala> import ControlStructures._! /!/import ControlStructures._! scala> times(2) { println("Hoorray :)")}! Hoorray :)! H!oorray :)! scala> unless (5 < 10) { println("Math stopped working.") }! /!/ Any = ()! scala> val ifNot = unless (2 + 2 != 4) { "Math still works." }! // Any = Math still works.!
  • 74.
    Scala - Patterns ⬤Structural Typing! ⬤Pimp-My-Library-Pattern Clueda AG 74
  • 75.
    Structural Typing ⬤Classedare described by methods and return types they provide! ⬤Works like duck typing but the checking happens in compile time, not run time Clueda AG 75 class Cowboy { def shout = "Yehaaw !" }! class Pirate { def shout = "Arrrgh !" }! ! def sayHelloTo( person : { def shout: String} ) = ! ! s"Me : Hello!n $person shouts ${person.shout}" val johnWayne = new Cowboy! ! sayHelloTo(johnWayne)! scala> sayHelloTo(johnWayne)! res4: String =! Me : Hello!! Cowboy@185f8f75 shouts Yehaaw ! val guybrush = new Pirate! ! sayHelloTo(guybrush)! scala> sayHelloTo(guybrush)! res5: String =! Me : Hello!! Pirate@29c356d3 shouts Arrrgh !
  • 76.
    Pimp-My-Library-Pattern ⬤Add newfunctions to existing libraries without changing the code! ⬤Like monkey patching! ⬤type safe! ⬤scoped Clueda AG 76
  • 77.
    Pimp-My-Library-Pattern : ExampleSource Clueda AG 77 object PimpString {! ! class WeatherString(s: String) {! def ☀ = { println(s"$s sunny!") }! def ☁ = "Dont't forget your ☂!“! }! ! implicit class ♔(name : String) {! def hail = s"Hail to king $name"! }! ! implicit def pimpString(in: String) : WeatherString = ! !new WeatherString(in)! }!
  • 78.
    Pimp-My-Library-Pattern : ExampleUsage Clueda AG ⬤Use with caution ! scala> import PimpString._! import PimpString._! ! scala> "Monday is" ☀! Monday is sunny!! ! scala> "???".☁! res8: String = Dont't forget your ☂ scala> val anotherKing = ♔("Louis")! anotherKing: PimpString.♔ = PimpString$$u2654@12359094! ! scala> val aKing = implicitly[♔]("George")! aKing: PimpString.♔ = PimpString$$u2654@5081371! ! scala> aKing.hail! res10: String = Hail to king George 78 scala> val guys = List("James", "Louis", "Franz-Ferdinand")! guys: List[String] = List(James, Louis, Franz-Ferdinand)! ! scala> guys map (_.hail)! res13: List[String] = List(Hail to king James, Hail to king Louis, Hail to king Franz- Ferdinand)
  • 79.
    Scala - imperative,object oriented, functional Clueda AG 79
  • 80.
    Scala -imperative, objectoriented, functional - Rules of the thumb ⬤functional if possible! ⬤Sometimes imperative is better and faster ! ⬤start out with val and immutable collections,switch to var or mutable collections if needed! ⬤Use object orientation to encapsulate side effects and imperative code Clueda AG 80
  • 81.
    Advantage of thefunctional approach ⬤short! ⬤no side effects -> easier to reason about! ⬤composeable Clueda AG 81
  • 82.
    Advantage of theimperative approach ⬤familiar! ⬤Eventually everything will be iterative after being translated to machine code Clueda AG 82
  • 83.
    Imperative vs. functional,Examples var i = 0! while (i < args.length) {! if ( i != 0 )! print(" ")! print( args(i) )! i += 1! }! println() Clueda AG 83 Imperative Functional var x = 1! var sum = 0! while (x <= 9999) {! sum += x! x += 1! }! (1 to 9999) foldLeft(0)(_ + _) (1 to 9999) sum println( args mkString " " ) println( ! args reduceOption ( (acc,arg ) => ! acc + " " + arg! )! )
  • 84.
    Imperative vs. functional,Examples 2 Clueda AG 84 Imperative Functional var i = null! var data = gettingData()! ! if (data != null && data.size > 0) ! ! i = data(0)! else ! ! i = 42! val i = ! ! if (data != null && data.size > 0)! ! ! data(0)! ! else! ! ! 42 val i = ! ! gettingData().headOption getOrElse 42
  • 85.
    Literatur: ⬤Wampler, D.,& Payne, A. (2009). Programming Scala. Sebastopol, CA: O'Reilly.! ⬤Odersky, M., Spoon, L., & Venners, B. (2008). Programming in Scala. Mountain View, Calif: Artima.! ⬤Malayeri, M. “Pimp My Library” Is An Affront To Pimpers Of The World, Everywhere! ⬤http://www.scala-lang.org! ⬤http://www.an-it.com Clueda AG 85
  • 86.
    Thanks for participating:) Clueda AG 86