Welcome !

?

Intro into Scala

For Java developers

Joost den Boer

Contractor, Senior developer, Scala enthusiast

@diversit

www.diversit.eu

THIS IS NOT A SCALA COURSE !!

Topics

  • What is Scala
  • Why Scala
  • Some Basics
  • Features
  • Frameworks
  • Getting started
  • Resources

What is Scala?

  • Functional and OO language
  • Runs on JVM
  • Started in 2001
  • By Martin Oderski (worked on Java Generics and javac)
  • @EPFL in Lausanne
  • European funds in 2011
  • Typesafe founded in 2011
  • Typesafe stack: Scala, Play, Akka, Activator

Why Scala?

  • It's Java 12+ available NOW
  • Binary compatible with Java
    • Good interoperability
    • Reuse of existing code/library
  • Loads of advanced features Java lacks
  • Java evolution too slow
  • Less  code, less bugs
  • Easier to read
  • Concurrency by design
    • Better suited for current and future hardware
    • Functional programming makes concurrency simpler
    • Immutability
    • Methods without side effects, repeatable
    • Complex functionality by composing multiple simple functions
    • Higher level of abstractions, more reuse of ideas
  • Superior Generics
  • Build custom DSL's

More why Scala?

Some basics

  • Everything is an object (extends Any)
    • Function is a first class object
    • As are singletons !
  • Every operation is a method
  • Every statement is an expression
  • Methods in methods
  • 'return' keyword is optional
  • call-by-name
  • Unchecked exceptions
    • Supports checked exceptions for Java compatibility

Features:

  • String interpolation
  • Traits
  • Concurrency, Reactive programming
  • Native XML support
  • Box types: Option
  • Powerfull Collection API
  • Case classes
  • Pattern matching
  • Currying
  • Implicits
  • Lambdas and closures

Features: String interpolation

val height = 1.9d
val name = "James"
println(f"$name%s is $height%2.2f meters tall")  // James is 1.90 
val name = "Piet"

s"Hello $name"
s"Sum is ${3 + 3}"
s"User name: ${user.name}"
"a\nb"

raw"a\nb"
"""a\nb"""

Extendable: create your own.

E.g. json"{ name:Piet }"

Feature: Traits

  • Like interfaces with vars and methods

Only compatible with Java when Trait only contains method definitions.

(might change with Java 8's default methods)

trait SomeService {
  val value = 1

  abstract def getValue: Int

  def toString = s"Value is ${value}"
}
class MySomeService extends SomeService
val mySomeService = new SomeService {}
  • Multiple inheritance (sort of, linear path)
trait Logging
trait SomeService extends Logging
trait OtherService extends Logging

class MySomeService extends SomeService with OtherService

Feature: Traits

  • Build-in DI support (Cake pattern)
    • override define values with other implementation
  • Dynamic @ runtime
val person = new Employee extends Management with HRM with CFO
  • Self typing
trait UserRepository {
    def find(id: Int): User
}

trait UserService {
    self: UserRepository =>

    def findUser(id: Int) = find(id)
}

Feature: concurrency, 

reactive programming

  • Immutability by default (shared state is hard)
  • Composable futures
  • Promises
  • .par()
  • Actors (Akka)

Feature: native xml support

// Create XML
val phoneBook =
    <phonebook>
       <descr>This is the <b>phonebook</b></descr>
       <entry>
         <name>Burak</name>
         <phone where="work">+41 21 693 68 67</phone>
         <phone where="mobile">+41 79 602 23 23</phone>
       </entry>
    </phonebook>
// Manupilate XML
val updatedPhonebook = phonebook match {
    case <phonebook>{ ch @ _* }</phonebook> =>
        <phonebook>{ ch }<entry> ... </entry></phonebook>
}
// XPath-like
phonebook \\ "phone" map (_.text)

// returns List[String]

Feature: Box types

Option's done right

No more 'null's and NPE's !

sealed abstract class Option[T]
final case class Some[T] extends Option[T]
object None extends Option[Nothing]
val i    = Some(1)    // Option[Int]
val user = Some(user) // Option[User]
val none: Option[User] = None // Option[User]

var noneWrong = None  // None.type
noneWrong = Some(1)   // Error: type mismatch; 
                      // found: Some[Int], required None.type
User u = someMethodReturningNUll();
u.getName(); // --> NPE

// Alternative
if (u != null) u.getName();

// Or
try {
    u.getName();
} catch (NullPointerException e) { .. }

In Java:

In Scala:

val user: Option[User] = someMethodReturningAUserOption()

u.map(_.name) // Option[String]

u.map(_.name).filter(_ contains "Piet") // Option[String]

u.map(_.name).filter(_ contains "Piet").getOrElse("Niet Piet") // String

u.map(_.name).filter(_ contains "Piet").orElse(Some("Niet Piet")) // Option[String]

Feature: Options (2)

Feature: Options (3)

For comprehension

for {
    user <- someMethodReturningAUserOption()
    name <- Some(user.name) if (user.name == "Piet")
} yield name // Option[String]

Pattern matching

someMethodReturningAUserOption match {
    case Some(user) if (user.name == "Piet") => ..
    case Some(User("Piet")) => .. // werkt ook
    case Some(user) => ..
    case None => ..
    case _ => .. // catches all others possibilities
}

Feature: Options (4)

Other box types:

  • Try ( Success or Failure )
  • Either ( Left or Right )
Try { u.name } // Try[String]: Success(name) or Failure(exception)

Alternative for Option for dealing with missing values

    Left = ok, Right = wrong

 

Can be used to gather multiple validation errors (Right: List[String])

Feature: Powerfull Collection API

In Java:

List<User> people = ...

List<String> adults = new ArrayList<String>();
for(User user : people) {
  if(user.getAge() > 18) {
    adults.add(user.getName());
  }
}

In Scala:

List[User] people = ...

val adults = people.filter(_.age > 18).map(_.name)
List<User> people = ...

List<String> adults = people.stream()
    .filter(p -> p.getAge() > 18)
    .map(User::getName())
    .collect(Collectors.toList());

In Java8:

Feature: Powerfull Collection API (2)

map, flatMap, filter, filterNot, find, forall, foreach, fold, mkString, drop, take, head, last, init, tail, exists, contains,
partition, slice, zip, reduce, reverse, sliding,
sum, max, min, product,
union, diff, intersect, ...

Some other functions:

class User {
  private String name;
  private Integer age;

  public User(String name, Integer age) {
    this.name = name;
    this.age = age;
  }

  public String getName() { return name; }
  public void setName(String name) {
    this.name = name;
  }

  public Integer getAge() { return age; }
  public void setAge(Integer age) {
    this.age = age;
  }

  public boolean equals(Object that) { ... }
  public int hashCode() { ... }
  public String toString() { ... }
}

Java:

Scala:

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

This includes:

  • Proper hashCode() and equals()
  • toString()
  • companion object
    • User("Piet", 33)

Feature: Case Classes

Feature: Pattern matching

  • matching collection types
  • maching case classes
  • vars from tuples
  • regex

Collection type matching

val aList = List(1,2,3)

// Example matching Lists
aList match { 
  case 1 :: twee :: rest => println(twee)
  case head :: tail => println(tail)
  case Nil => println("Nothing")
}

Feature: Pattern matching

Case class matching

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

val piet = User("Piet", 80)

piet match {
    case u @ User(name, _) => ..
    case _ => ..
}
val userList = List(User("Piet", 80), User("Ruud", 54), User("Kees", 23))

userList map {
    case User(name, age) if age > 18 => name
    case _ => "too young"
}

val names = userList map {
    case User(name, age) if age > 18 => Some(name)
    case _ => None
} // List[Option[String]]

names.flatten // List[String] without the None's

Feature: Pattern matching

Matching Tuples

val t = (1, "abc", List(1,2,3))

val (i, s, l2) = t // i=1, s="abc", l2=List(1,2,3)

t match {
  case (_: Int, _, _) => println("Int")
}

Regex matching

val regex = """^INFO: (.*)$""".r

val regex(msg1) = "INFO: testing" // msg1 = "testing"

val msg2 = "INFO: testing" match {
  case regex(msg) => msg
} // msg2 = "testing"

Feature: currying

Introducted by Moses Schönfinkel.

Later developed by Haskell Curry.

"currying is the technique of translating the evaluation of a function that takes multiple arguments (or a tuple of arguments) into evaluating a sequence of functions, each with a single argument (partial application)"

// uncurried
def sum(x: Int, y: Int): Int = x + y
sum(1,4) // 5

Feature: currying

// curried
def sum: Int => Int => Int = x => y => x + y
val addOne = sum(1) // Int => Int = <function1>
addOne(2) // 3

sum(1)(4)
  • Multiple argument lists.
  • Partially applied funtions

To curry and uncurry

// To curry
def sum1(x: Int, y: Int) = x + y // sum1: (x: Int, y: Int)Int -> NOT a Function!

val fSum1 = sum1 _ // (Int, Int) => Int = <function2> -> Function taking 2 args

val cSum1 = fSum1.curried // res48: Int => (Int => Int) = <function1>
Function.uncurried(cSum1) // (Int, Int) => Int = <function2>

Partial functions: PartialFunction[A-, B+]

// Actor's receive method

def receive: Receive = {
    case SomeMessage(content) => // do something with content
}

'case' matching to create partial function

val list = List(1,2,3,4,5,6)

val result = list.collect { case x if x > 3 => x }

// What is result?
result == List(4,5,6)

Feature: implicits

Java implicits:

  • autoboxing
  • default constructor
  • calling super() in constructor

To automatically determine or refer to a value

Scala implicits:

  • Automatically determine values for arguments.
  • Automatically find converters

Implicits are looked up in specific order: Scopes

Feature: implicits

implicit val one: Int = 10

def addOne(x: Int)(implicit y: Int) = x + y // (x: Int)(implicit y: Int)Int

addOne(3) // 4

Bad example!

Implicits look at types, not at value names.

So, use types when using implicit values.

type One = Int // wrong: will still match all implicit Int's

type IntCheck = Int => Boolean // already more specific

implicit val biggerThanTwo: IntCheck = x => x > 2

def check(x: Int)(implicit checker:IntCheck) = checker(x)
class Adder(value: Int)

implicit val one = Adder(1)

def addOne(x: Int)(implicit y:Adder) = x + y

Feature: implicits

Implicit conversions: Very powerfull !!

Also here: use Types

class Adder(val x: Int)

implicit def adderToString(a: Adder) = s"Adder value: ${a.x}"

def someMethod(s: String) = println(s)

someMethod(new Adder(10)) // implicit conversion to String!

Extend existing classes with new functionality!

(like Caterogies in Objective C)

implicit class IsTodayDate(val date: java.util.Date) extends AnyVal {
    def isToday: Boolean = new Date().equals(date)
}

new java.util.Date().isToday

Implicit Value classes are NOT instanciated!

Feature: implicits

Convert between Java <-> Scala types: 

 

Best practive: Use JavaConverters, not JavaConversions !

import scala.collection.JavaConverters._

val sl = new scala.collection.mutable.ListBuffer[Int]
val jl : java.util.List[Int] = sl.asJava
val sl2 : scala.collection.mutable.Buffer[Int] = jl.asScala
assert(sl eq sl2)

Lambdas and Closures

Lamda expression: a function defined, and possible called, without being bound to an identifier.

Closure: a function which accesses non-local variables

  • Java <8: CallBack objects
  • Java 8  : Lambda expressions
  • Scala   : Fully functional, Function is an object
// Assume Person class with name and age.

List<Person> persons = new ArrayList() {{
    add(new Person("Piet", 40));
    add(new Person("Kees", 18));
    add(new Person("Eva", 18));
}};

Map<Integer, List<String>> personsByAge = persons.stream()
        .filter(p -> p.age > 16)
        .collect(
                Collectors.groupingBy(
                        p -> p.getAge(),
                        Collectors.mapping(p -> p.getName(), Collectors.toList())
                )
        );

System.out.println(personsByAge);
// Assume Person class with name and age.

List<Person> persons = new ArrayList() {{
    add(new Person("Piet", 40));
    add(new Person("Kees", 18));
    add(new Person("Eva", 18));
}};

Map<Integer, List<String>> personsByAge = persons.stream()
        .filter(personsOver16())
        .collect(
                Collectors.groupingBy(
                        getPersonAge(),
                        personNamesList()
                )
        );

System.out.println(personsByAge);
static Predicate<Person> personsOver16() {
    return p -> p.getAge() > 16;
}

static Function<Person, Integer> getPersonAge() {
    return p -> p.getAge();
}

static Function<Person, String> getPersonName() {
    return p -> p.getName();
}

static Collector<? super Person, ?, List<String>> personNamesList() {
    return Collectors.mapping(getPersonName(), Collectors.toList());
}


// Scala oplossing

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

val persons = List(Person("Piet", 40), Person("Kees", 18), Person("Eva", 18))

def personsNameList: List[Person] => List[String] = ps => ps.map(_.name)

val personsByAge = persons.groupBy(_.age).mapValues(personsNameList)

println(personsByAge)

How to do this in Java?

def sum: Int => Int => Int = x => y => x + y

sum(1)(3) // 4
static Function<Integer,Function<Integer, Integer>> fSum() {
    return x -> y -> x + y;
}
fSum().apply(1).apply(2);

Advanced features

Macros

  • Extend the language yourself
  • AST manipulations
  • Experimental

Reflection

  • Type info at runtime
  • new in 2.10
  • Often used with implicits

Monads, Monoids, Functors, Applicatives

Advanced features

Advanced Generics

  • E.g. only support sum() method on list of values
  • E.g. Builder pattern, enforce order of methods

Covariant, Contravarant, Invariant

Covariant: convert from wider to narrower type.

Contravariant: convert from type to wider type.

Invariant: Not able to convert.

Frameworks

  • Testing: ScalaTest, Specs2
  • Web: Play, Lift
  • Rest: Spray, Scalatra
  • Reactive: Akka
  • Tools: Scalaz, Shapeless

Getting started

IntelliJ, Eclipse

SBT, Maven Plugin

Download from Typesafe, Homebrew (Mac)

Mixing with Java: Scala compile first (default)

  • Precompiles public Java classes api
  • Then compiles Scala classes
  • Then compiles Java classes

Testing excelent way to get started!

Resources

  • Typesafe.com
    • Several learning resources
    • Typesafe Activator
  • ScalaDocs
  • Loads of online presentations and slides
  • Parlays.com (Devoxx and ScalaDays videos)
  • Twitter Scalaschool
  • CakeSolutions: Week-in-Scala blog
  • Coursera course
    • 'Functional Programming in Scala'
      • Start september 15th !
    • 'Reactive Programming'
  • Danial Westheide's 'Neophyte's Guide to Scala' 
    • http://danielwestheide.com/scala/neophytes.html

?

Scala intro for Java developers

By Joost den Boer

Scala intro for Java developers

An introduction into the cool feature of Scala you're missing out on when using Java.

  • 1,490