introduction to scala - tu braunschweig · introduction to scala felix geilert. slides will be...

32
Introduction to Scala Felix Geilert

Upload: others

Post on 22-May-2020

18 views

Category:

Documents


0 download

TRANSCRIPT

Introduction to Scala

Felix Geilert

Slides will be available online

scala-bs.de

What is Scala

Scale Out - Modulare Programmiersprache

Scalable Language

Devices – Runs on the JVM

Paradigm – Support for OOP and FP

Full support for Java Libraries

FP Code in Scala is similar to Haskell

Scala was designed with parallelization in mind

From Java to Scala

def programming(input: Java): Scala

Variables and Values

Scala is a strongly typed languageTypes are checked at compile-time

Values

Variablesvar count = 0count = 1

val fix_value = 42

val fix_value2 = “Typesafe!”

Classes• Scala is public by default (there

is no explicit public keyword)

• Constructor is integrated into the definition• Overloading is still possible

• traits can be seen as combination of abstract class and interface

• not allowed to have a constructor, but can be partially implemented

class HelloScala(param: String) {def this = this(“Hello Scala”)def hello = println(param)

}

trait HelloTrait {def hellodef greet = println(“Wad up?”)

}class HelloScala(param: String) implements HelloTrait {

def this = this(“Hello Scala”)def hello = println(param)

}

• def keyword is used to define functions

• traits are mix-ins: They can implement functions and a class can be a mix of multiple traits!

Objects

aka Singleton made easy

object MySingleton {def someNumber: Int = {

println(“a cool number”)42

}}

println(MySingleton.someNumber)

• Defines an object which provides static functions

• Therefore there will always only be one instance

• Scala returns the expression in the last line. No explicit return needed!

Objects

also a good companion

• Basically holds all static methods• Can be used to implement the factory

pattern

class HelloScala(param: String) {def this = this(“Hello Scala”)def hello = println(param)

}

object HelloScala {def create: HelloScala = HelloScala(“Singleton”)

}

Applications

object HelloScala {def main(args: Array[String]) {

println(“Hello”)}

}

class HelloScala extends App {println(“Short Hello”)

}

Main Method – Java Style

Main Method – Scala Style

We use object here, to make the method static

Take Home Points

Scala is type safe – All types are checked at compile time

var/val to create variables and constants

Singletons can be created using objects

Traits are a mix of abstract class and interface

They can define which type can implement them (self-trait)

Why should we use Scala?

Boilerplate

No Semicolons App instead of main method

Singletons made easy Typesafe – Less Error Prone

Packages are not restricted to foldersNo explicit return

And the list goes on…

Remember Maven?

And all the fun you had creating those XML’s?

Simple Built Tool

name := “HelloScala”

scalaVersion := “2.11.4”

version := “1.0-SNAPSHOT”

val akkaV := “2.3.4”

libraryDependencies ++= Seq(“com.typesafe.akka” %% “akka-actor” % akkaV,“com.typesafe.akka” %% “akka-remote” % akkaV,“com.typesafe.akka” %% “akka-cluster” % akkaV

)

• define project name

• define Version of Scala. SBT will load it, so it does not have to be installed

• some library dependencies. You can use maven repositories here!

Functional Programming

+

Functional Programming

Pure Functions

Based on pure functions

No Side-Effects

Referential Transparency

Everything that leaves the function

Side-Effect =

No Global StateFunctions only depend on their input parameters

Therefore it does not matter in which order functions are executed

Pure Functions

A small Example

var counter = 0

def increaseNumber(x: Int): Int = {if (counter < 100) {

println(“get a new number”)counter = counter + 1x + counter

}else

throw new Exception(“too high”)}

val num1 = increaseNumber(10) // will be 11val num2 = increaseNumber(5) // will be 7

Global State!

val num2 = increaseNumber(5) // will be 6val num1 = increaseNumber(10) // will be 12

No Referential Transparancy!

Pure Functions

A small Example

def increaseNumber(x: Int, counter: Int): (Int, Int) = {if (counter < 100) {

println(“get a new number”)(x + counter + 1, counter + 1)

}else

throw new Exception(“too high”)}

val num1, c1 = increaseNumber(10, 0) // will be 11val num2, c2 = increaseNumber(5, 1) // will be 7

Side-Effects

Scala does have integrated Tuple Types!

Pure Functions

A small Example

def increaseNumber(x: Int, counter: Int): Option[(Int, Int)] = {if (counter < 100) {

Some( (x + counter + 1, counter + 1) )}else

None}

val num1Opt = increaseNumber(10, 0) // will be 11val (num1, c1) = num1Opt.getOrElse( (0,0) )val num2Opt = increaseNumber(5, 1) // will be 7val (num2, c2) = num2Opt.getOrElse( (0,0) )

Option-MonadeCan have 2 types:Some with embedded valueNone

Split tuple in values

ListsQuite like Haskell

Recursive Data-Structure

sealed trait List[+A]case object Nil extends List[Nothing]case class List[+A](head: A, tail: List[A]) extends List[A]

val ls1 = List()= Nil

val ls2 = List(1)= List(1, Nil)

val ls3 = List(1,2,3,4)= List(1,List(2,List(3, List(4, Nil))))

Nothing is the Subclass of everything

Pattern Matching

val ls = List(1,2,3,4)

ls match {case head :: Nil => println(“The last of it’s kind!”)case head :: tail if head == 4 => println(“It is a four!”)case head :: tail => println(s“It is a $head”)case Nil => println(“There is nothing here.”)

}

Order is important. This will not be matched if it stands after head::tail

There can be additional conditions attached to the cases

Case Classes

case class Person(name: String, age: Int)

Advantage: Can easily be constructed and destructed!Also it is easy to transform them into a string (and compare them)

val p1 = Person(“Lawyer”, 42)println(p1)

Output: Person(Lawyer, 42)

Why do we need that?

Case ClassesPattern matching

Apply/Unapplyval p1 = Person(“John Doe”, 42)p1 match {

case p: Person => p.namecase _ => “Unknown”

}

p1 match {case Person(name, age) => namecase _ => “Unknown”

}

Easy to construct / deconstruct classes

Person.apply(“John Doe”, 42)

Person.unapply(p1) : Option[(String, Int)]

p1 match {case Person(name, age) if age > 42 => namecase _ => “Unknown”

}

Partial Functions

Functions that are not defined for all possible input values

Partial Functions are used all over ScalaList(1,2,3) foreach {

case x: Int => println(x)}

def fraction(value: Int) = 10 / value

Obviously not defined for value = 0

val fraction: PartialFunction[Int, Int] = {case value if value != 0 => 10 / value

}

List(1,2,3) map {case x: Int => x + 1

}

try {//code…

}catch {

case e: IOException => println(“oh no”)}

List(1,2,3) match {case head :: tail => println(head)

}

Recursion

Recursion through Lists on the base of Partial Functions

def filter(ls: List[Int], value: Int): List[Int] = {@annotation.tailrecdef loop(ls_in: List[Int], ls_out: List[Int]): List[Int] = ls_in match {

case head :: tail if head == value => loop(tail, ls_out)case head :: tail => loop(tail, ls_out :+ head)case Nil => ls_out

}

loop(ls, List())}

Inner Function

Tail Recursive Function calls

Call in the outer function

Comprehensions

Comprehensions are generalized for loops

for (enumerations) yield {codeblock}

Codeblock will be evaluated for each possibility in the enumerations. It returns a sequence of the

results of the codeblock

val ls1 = List(1,2,3)val ls2 = List(“a”, “b”, “c”)

val ls3 = for (i <- ls1, j <- ls2) yield (i,j)

Generate a tuple for each possible combination

Output: List((1,a), (1,b), (1,c), (2,a), (2,b), (2,c), (3,a), (3,b), (3,c))

implicitsUnique to Scala

Based on type safety: allows to create functions for specific types that are used implicitly

case class Person(name: String, age: Int)

implicit def convertPerson(name: String) : Person = Person(name, 42)

def showPerson(p: Person) = println(p)

showPerson(“John Doe”)

• Compiler detects, that type string is given buttype person required

• Also know that there is a function he isallowed to use implicitly to convert a stringinto a person

As a result, each implicit conversion has to be unique in terms of types!

Duck typing / Structural Subtyping

Idea: define a parameter by the functions it has, not by the type

def duckTyping(input: {def quack(value: String): String} ) = println(duck.quack(“Hello Scala”))

Input can be anything that has a quack function with the given signature

val x = new AnyRef {def quack(value: String): String = “I AM ” + value

}duckTyping(x)

object Duck {def quack(value: String): String = “simple ” + value

}duckTyping(Duck)

AnyRef is the highest class in Scala HierarchyIt stands for anything

Lazy EvaluationHaskell is always lazy

Scala has specific keyword for that

Specifies when an expression is evaluated

def defTest = {println(“def test”)42

}

val valTest = {println(“val test”)42

}

lazy val lazyTest = {println(“lazy test”)42

}

defTestOutput:def test42

val test

valTestOutput:42

lazyTestOutput:lazy test42

lazyTestOutput:42

Scala vs Java

Scala generalizes almost anything

Interfaces Traits

Switch-Case Pattern Matching

Singleton Pattern Objects

Loops Comprehensions

Scala vs Java

Scala has some features that do not exist in Java

Implicits Duck Typing

Lazy Evaluation Self Trait

Case Classes Partial Functions

And there is more…

Macros Immutable Collections

Scala vs Java

Scala allows to easily create DSL (Domain Specific Languages)This allows you to add new elements to the languageYou miss something in the language? Add it yourself!

“My Class” should “double a number” in {MyClass.double(4) should be (8)

}

ScalaTest – DSL to create unit tests

Scala User Group

2. Thursday of every month in IZ 161

Many interesting Topics around Scala

Everybody is welcome, no knowledge in Scala required!

@scala-bs