Why Scala is the better Java

Post on 08-Jan-2017

371 views 0 download

Transcript of Why Scala is the better Java

Why Scala is the better Java

Thomas KaiserTechnologieplauscherl

14.01.2016

Agenda• Why this talk• Cool language features• Pitfalls and how to avoid them• Resources

Quick survey• Who... • ... Writes Java code for production?• ... Has ever written any Scala code?• ... Has ever written Scala for production?

• Me• Java background (Spring, Hibernate, Grails, GWT, Android)• Scala webapp w/ Postgres, Mongo, Play, Angular, REST

What is Scala• JVM based functional/OO language• Powerful type system• Traits/mixins• Higher-order functions• Pattern matching• Concurrency abstractions

Why this talk• People are interested in Scala, but also afraid?• Scala is extremely powerful and flexible• Syntax• Huge library• Lots of ways to do the same thing• Very intimidating type system

• BUT! You don‘t have to use any of the advanced features and still benefit massively

Why Scala• Extremely expressive (LOC--)• Static typing• Very clean style comes built-in• Awesome (awesome) library (collections etc)• Writing Scala code is actually fun!

Language features (why I love Scala)• Tuples• String concatenation• Local functions• Import aliases• Super-easy collection/map creation• Powerful collections library• Traits• Case classes• Pattern matching• Function values/function literals• Multiple parameter lists• Option[T]• For-Comprehensions• Everything is a value• Syntax flexibility • Type inference• JSON/XML handling• Scalatest/specs2• Implicit conversions• Annymous/structural types, type aliases• Algebraic data types

S vs. J: Boilerplatepublic class User { private String name; private List<Order> orders;

public User() { orders = new ArrayList<Order>(); } public String getName() { return name; } public void setName(String name) { this.name = name; } public List<Order> getOrders() { return orders; } public void setOrders(List<Order> orders) { this.orders = orders; }}

public class Order { private int id; private List<Product> products;

public Order() { products = new ArrayList<Product>(); }

public int getId() { return id; } public void setId(int id) { this.id = id; }

public List<Product> getProducts() { return products; } public void setProducts(List<Product> products) { this.products = products; }}

public class Product { private int id; private String category;

public int getId() { return id; } public void setId(int id) { this.id = id; }

public String getCategory() { return category; } public void setCategory(String category) { this.category = category; }}

S vs. J: Boilerplate

case class User(name: String, orders: List[Order])

case class Order(id: Int, products: List[Product])

case class Product(id: Int, category: String)

S vs. J: Standard use case – extract data• Get products of a User

public class User {...

public List<Product> getProducts() { List<Product> products = new ArrayList<Product>(); for (Order order : orders) { products.addAll(order.getProducts()); } return products; }}

S vs. J: Standard use case – extract data• Get ordered products of a User

case class User(name: String, orders: List[Order]) { def products = orders.flatMap(o => o.products)}

S vs. J: Remove x highest valuespublic static List<Integer> removeHighestValuesJ6(List<Integer> values, int amount) {

List<Integer> localValues = new ArrayList<>(values); Collections.sort(localValues);

int toIndex = localValues.size() - amount; if (toIndex < 0) { toIndex = 0; } return localValues.subList(0, toIndex);}

public static List<Integer> removeHighestValuesJ8(List<Integer> values, int amount) {

Collections.sort(values); // in-place! boo! Collections.reverse(values); // in-place!

List<Integer> result = values.stream() .skip(amount) .collect(Collectors.toList()); return result;}

S vs. J: Remove x highest values

def removeHighestValues(list: List[Int], amount: Int) = { list.sorted.reverse.drop(amount)}

For comprehensions each++

for (i <- 1 to 7) print(i) // 1234567

for (i <- 1 to 7 if i % 2 == 0) print(i) // 246

case class Person(age: Int)

val persons = for (i <- 20 to 35 by 5) yield Person(i)// Person(20), Person(25), Person(30), Person(35)

Pattern matchingcase class Person(name: String, age: Int)

val p1 = Person("thomas", 29)val p2 = Person("dominik", 32)

p2 match { case Person("thomas", 29) => "exactly that person" case Person(_, age) if age > 30 => "anyone over 30" case p : Person => s"just binding to a variable (${p.name})"}

Pattern matching

val list = List(1, 2, 3)list match { case 1 :: 2 :: rest => "list starts with 1,2 and has " + rest.length + " more"}

Everything is a value

val bool = trueval yepNope = if (bool) "yep" else "nope"

case class AuthUser(email: String, roles: Set[String])

val currentUser = AuthUser(”user", Set("ADMIN"))

val isAuthorized = currentUser match { case AuthUser(_, roles) if roles.contains("ADMIN") => true case _ => false}

Everything is a valuedef russianRoulette() = if (Random.nextInt(6) == 0)

throw new RuntimeException(“bang“) else

"phew“

val dangerousResult: String = try { russianRoulette() } catch { case RuntimeException => "dead :(“ }

Implicit conversions

val hello: String = "hello"hello.emphasize // Error:(32, 8) value emphasize is not a member of String

„Pimp my library pattern“

implicit class PimpedString(base: String) { def emphasize = base + "!!!11"}

import PimpedStringval pimpedString = hello.emphasize // hello!!!11

Implicit conversions

for (i <- 1 to 7) <=> 1.to(7) <=> val r: Range = new RichInt(1).to(7)

DSLsclass HelloWorldSpec extends Specification { "Hello world" should { val hw = "Hello world"

“be 11 chars long" in { hw should have size 11 }

"start with hello" in { hw should startWith "hello“ } }}

DSLs

"show off some mocking DSL" in {

val m = mock[List[String]] m.get(0) returns “0"

// .. code under test ...

there was one(m).get(0)}

DSLs

val messageFlow = filter { payload: String => payload == "World" } --> transform { payload: String => "Hello " + payload } --> handle { payload: String => println(payload) }

messageFlow.send("World") // "Hello World"

Implicit conversions

for (i <- 1 to 7) <=> 1.to(7) <=> val r: Range = new RichInt(1).to(7)

Map(1 -> "one") <=> 1.->("one") <=> val entry : (Int, String) = new ArrowAssoc[Int](1).->("one”)

val x = Future { ... }Await.result(x, 5 seconds) <=> new DurationInt(5)

Pitfalls• Implicits can be confusing • Many different codestyles in the wild• Hard to understand libraries• Yet another build tool (SBT)

Take away• Just do it!• You can always go back or mix Java and Scala code• ... But you won‘t

• Be wary of advanced language features• Don‘t be scared, you don‘t have to use anything• Use it as a very expressive, fun, supercharged Java• ... And you won‘t look back

• „Scalable language“

Resources• http://scala-lang.org/• http://docs.scala-lang.org/cheatsheets/ • List of links (!!)• Learning functional programming without growing a neckbeard• https://github.com/pocorall/scaloid (Scala4Android, super cool)