JDays Lviv 2014: Java8 vs Scala: Difference points & innovation stream

45
JAVA8 / SCALA Difference points & innovation streams Ruslan Shevchenko. <[email protected]> https://github.com/rssh @rssh1

description

Slides from talk on JDay Lviv: 2014 http://www.jday.com.ua/ - comparison between scala and java8 features.

Transcript of JDays Lviv 2014: Java8 vs Scala: Difference points & innovation stream

JAVA8 / SCALADifference points & innovation streams

Ruslan Shevchenko. <[email protected]> https://github.com/rssh @rssh1

JAVA / SCALA

• Java & Scala significantly different

• Exists innovations: scala => java & java=>scala

• What language I must learn ?

• All of them !

SCALA JAVA8

public class Person { private String firstName; private String lastName;

String getFirstName() { return firstName; } void setFirstName(String v) { firstName = v; }

…………………. int hashCode() { if (firstName==null) { if (secondName==null) { return 0; } else { return secondName.hashCode(); } } else{ if (secondName==null) { } } } boolean equals() { …. }

}

case class Person ( firstName: String lastName: String )

SCALA JAVA8

public class Person extends DTOBase { public String firstName; public String lastName; }

case class Person ( firstName: String lastName: String )

SCALA => JAVA

Similar :

lambda-expressions

traits / default methods

collections API with hight-order functions

LAMBDA EXPRESSIONS list.sort((x,y)-> { int cmp = x.lastName.compareTo(y.lastName); return cmp!=0 ? cmp : x.firstName.compareTo(y.firstName) }

list.sort((x,y) => { val cmp = x.lastName.compareTo(y.lastName) if (cmp!=0) cmp else x.firstName.compareTo(y.lastName) }

Java

Scala

LAMBDA EXPRESSIONS var (maxFirstLen, maxSecondLen) = (0,0) list.foreach{ x => maxFirstLen = max(maxFirstLen, x.firstName.length) maxSecondLen = max(maxSecondLen, x.secondName.length)}

Java

Scala

Closures can’t modify environment context…………………….

TRAITS/DEFAULT METHODS

trait AsyncInput[T]{ def onReceive(acceptor: T=>()): Unit

def read: Future[T] = { Promise p = Promise[T]() onReceive(p.complete(_)) p.future }

}

interface AsyncInput<T>{ void onReceive(Acceptor<T> acceptor)

default void read(): Future<T> { final CompletableFuture<T> promise = new CompletableFuture<>(); onReceive( x -> promise.complete(x) ); return promise; } }

Scala Java

TRAITS/DEFAULT METHODS

trait LoggedAsyncInput[T]{ this: AsyncInput => override def onReceive(acceptor: T => ()) = super.onReceive(x => { println(s“received:${x}”) acceptor(x) })

}

ScalaJava

aspects ? …

TRAITS/DEFAULT METHODS

trait LoggedAsyncInput[T]{ override def onReceive(acceptor: T => ()) = super.onReceive(x => { println(s“received:${x}”) acceptor(x) })

}

ScalaJava

aspects ? …

trait MyToString{

override def toString = s”[${super.toString}]”

}

TRAITS/DEFAULT METHODS

Java default interface: dispatch across class/interface hierarchy

Scala traitsbuilding hierarchy with process of linearization

STREAMING COLLECTIONSpersons.stream().filter( x -> x.firstName.equals(”Jon”) ).collect(Collectors.toList())

persons.filter(_.firstName == “Jon”)

Java

Scala

STREAMING COLLECTIONSpersons.stream().filter( x -> x.firstName.equals(”Jon”) ).collect(Collectors.toList())

Java

Reason - existing API

Don’t want to mix old and new API in one

Operation composition without reiterating.

PARALLELpersons.parallelStream().filter( x -> x.firstName.equals(”Jon”) ).collect(Collectors.toList())

persons.par.filter(_.firstName == “Jon”)

Java

Scala

SQL

..??***8dc

persons.filter(_.firstName === “Jon”)

Scala (slick)

Java ?

?

SQL

..??***8dc

persons.filter(_.firstName === “Jon”)

Scala (slick)

Java (http://jinq.org)

dbStream(em,Person.class).filter( x -> x.firstName.equals(“Jon”) ).list

SQL (INSIDE ?)

persons.filter(_.firstName === “Jon”).toList

Scala (slick)

TableQuery[Expr[Person]]

Expr[String], Expr[StringConstant] => Expr[Boolean]

SQL (INSIDE ?)

persons.filter(_.firstName === “Jon”).toList

Scala (slick)

TableQuery[Expr[Person]]

Expr[String], Expr[StringConstant] => Expr[Boolean]

Query[Expr[T]], Expr[Boolean] => Query[Expr[T]]

Query { … generateSql( .. ) }

SQL (INSIDE)

..??***8dc

Java (http://jinq.org)

dbStream(em,Person.class).filter( x -> x.firstName.equals(“Jon”) ).list

DbStream<Person>

Person => Boolean

SQL (INSIDE)

..??***8dc

Java (http://jinq.org)

dbStream(em,Person.class).filter( x -> x.firstName.equals(“Jon”) ).list

Person => Booleanfor sql generation we need:

analyse bytecode symbolic interpretation collect trace

generate sql

// runtime-only, not very fast

SQL (INSIDE)Java (http://jinq.org)

// runtime-only, not very fast

complex, state-of-the-art technology all work is in runtime

unable to check function correctness in compile-time

Scala (slick)relatively simple

compile-time analysis, runtime generationverification in compile time

JAVA => SCALA: SAM

trait AsyncInputOutput[T]{ def onReceive(acceptor: T=>()): Unit

def onSend(generator: ()=>T): Unit}

interface AsyncInputOutput<T>{ void onReceive(Acceptor<T> acceptor)

void onSend(Generator<T> generator)

………………}

Scala Java

SAM• SAM-type = Type with Single Abstract Method

• Method require SAM-type => we can pass lambda-expression to one.

• In scala:

• 2.11 — with -Xexperimental

• 2.12 — by default

SAM

trait AsyncInputOutput[T]{ Function1.class def onReceive(acceptor: T=>()): Unit

Function1.class def onSend(generator: ()=>T): Unit}

interface AsyncInputOutput<T>{ Acceptor.class void onReceive(Acceptor<T> acceptor)

Generator.class void onSend(Generator<T> generator)

………………}

Scala: JVM Java

JIT inlining impossible Jit inlining is possible

SCALA=>JAVA; JAVA=>SCALA

• Java use ‘additional’ streaming API [not ideal, better than before]

• Scala library can’t utilize SAM conversion [not ideal, better than before]

• So, we have place for something 3-rd ?

• Evolution: all ‘ideal’ shifts ….

FUTURE EVOLUTION

• 2 Groups

• which will be integrated in java 9,10, 11, .. if exists.

• [ FORTRAN 90 is object-oriented. Do you know this (?)]

• case classes, type inheritance.

• which represent essential different aspect, not present in java

CASE CLASSES

..??***8dc

case class Person(firstName: String, lastName: String)

p match { case Person(“Jon”,”Galt” ) => “Hi, who are you ?” case Person(firstName, lastName) => s”Hi, ${firstName}, ${lastName}” case _ => “You are not person”}

ML-style pattern matching, 1973scala, kotlin, ceylon, swift

FUTURE EVOLUTION• essential different aspect, not present in java:

• internal DSL

• flexible syntax

• call by name

• macros

• Variance

• strong typing

• implicit context

FLEXIBLE SYNTAX

..??***8dc

def +++(x:Int, y:Int) = x*x*y*y

1 to 100 == 1.to(100)

future(1) та future{1}

def until(cond: =>Boolean)(body: => Unit): Unit

CALL BY NAME

..??***8dc

def dountil(cond: =>Boolean)(body: => Unit): Unit ={ var quit = false; while(!quit) { body quit = !cond }}

First introduced in Algol 68

var x = 0dountil(x != 10)(x+=1)

OWN SYNTAX

..??***8dc

object Do{ def apply(body: =>Unit) = new DoBody(body)}

class DoBody(body: => Unit){ def until(cond: =>Boolean): Unit = { body; while(!cond) body }}

Do { x = x+1 } until (x<10)

BASIC DSL:)

..??***8dc

object Lunar extends Baysick { def main(args:Array[String]) = { 10 PRINT "Welcome to Baysick Lunar Lander v0.9" 20 LET ('dist := 100) 30 LET ('v := 1) 40 LET ('fuel := 1000) 50 LET ('mass := 1000) 60 PRINT "You are drifting towards the moon." 70 PRINT "You must decide how much fuel to burn." 80 PRINT "To accelerate enter a positive number" 90 PRINT "To decelerate a negative" 100 PRINT "Distance " % 'dist % "km, " % "Velocity " % 'v % "km/s, " % "Fuel " % 'fuel 110 INPUT 'burn 120 IF ABS('burn) <= 'fuel THEN 150 130 PRINT "You don't have that much fuel" 140 GOTO 100

http://blog.fogus.me/2009/03/26/baysick-a-scala-dsl-implementing-basic/

..??***8dccollection.foreach(x => doSomething)

‘FOR’ SPECIAL SYNTAX..??***8dcfor( x <- collection) doSomething

=

..??***8dcfor(x <- fun1 if (x.isGood); y <- fun2(x) ) yield z(x,y)

=

..??***8dcfun1.withFilter(_.isGood). flatMap(x => fun2.map(y=>z(x,y)))

..??***8dccollection.foreach(x => doSomething)

‘FOR’ SPECIAL SYNTAX..??***8dcfor( x <- collection) doSomething

=

..??***8dcfor(x <- collection)

yield something

=

..??***8dccollection.map( x => something)

‘FOR’ SPECIAL SYNTAX..??***8dc

=

..??**8dc

for(r <- rows; c <- cell(r) ) ….

rows.flatMap(r => cell.map(c =>….))

..??***8dcfor(x <- c if p(x)) …. =

..??***8dcc.withFilter(x->p(x)) …

..??***8dccollection.foreach(x => doSomething)

‘FOR’ SPECIAL SYNTAX..??***8dcfor( x <- collection) doSomething

=

..??***8dcfor(x <- fun1 if (x.isGood); y <- fun2(x) ) yield z(x,y)

=

..??***8dcfun1.withFilter(_.isGood). flatMap(x => fun2.map(y=>z(x,y)))

FOR-SYNTAX• own foreach: possible to use ‘for’

• ‘Monadic interfaces’

• //foreach, map, flatMap, withFilter

• // scala-virtualized (not in standard)

• define own function for all syntax constructions

IMPLICITimplicit def f(x): y

Use x as y

add ‘own’ methods to existing classespass contextdefine type-guided expressions

FUTURE: MONADIC

..??***8dc

for( x <- Future{ calculate x }; y <- Future{ calculate y } ) yield x(x,y)

Future[T]foreach — do something after competitionmapflatMap — future composition

MACROS

..??***8dc

object Log {

def apply(msg: String): Unit = macro applyImpl

def applyImpl(c: Context)(msg: c.Expr[String]):c.Expr[Unit] = { import c.universe._ val tree = q"""if (Log.enabled) { Log.log(${msg}) } """ c.Expr[Unit](tree) }

Log(msg)if (Log.enabled) {

Log.log(msg)}

MACROS

Reduce boilerplate code

Fast code generation for HPC

Deep AST transformations

example: async

ASYNC AS MACROS

..??***8dc

async { val x = async{ long-running-code-x } val y = async{ long-running-code-y } val z = await(x) + await(y)}

Rewritten as state machine without blockingImplemented as library (without language change)

async: T => Future[ T ]await: Future[T] => T

MACROS

async/await

jscala (generate javascript)

miniboxing (analog @specialized)

JAVA/SCALA • Java - stable domain, mapped to classes and objects.

• Scala - in complex area, where new level of abstractions needed.

• In the beginning of PL

evolution, but totally new dimension

THANKS FOR ATTENTIONRuslan Shevchenko <[email protected]>

@rssh1

https://github.com/rssh