JAVA8 / SCALA
Difference points & innovation streams
Ruslan Shevchenko. <ruslan@shevchenko.kiev.ua>
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) })
}
Scala
Java
aspects ? …
TRAITS/DEFAULT METHODS
trait LoggedAsyncInput[T]
{
override def onReceive(acceptor:T => ()) =
super.onReceive(x => {
println(s“received:${x}”)
acceptor(x) })
}
Scala
Java
aspects ? …
trait MyToString
{
override def toString = s”[${super.toString}]”
}
TRAITS/DEFAULT METHODS
Java default interface:
dispatch across class/interface hierarchy
Scala traits
building hierarchy with process of linearization
STREAMING COLLECTIONS
persons.stream().filter(
x -> x.firstName.equals(”Jon”)
).collect(Collectors.toList())
persons.filter(_.firstName == “Jon”)
Java
Scala
STREAMING COLLECTIONS
persons.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.
PARALLEL
persons.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 => Boolean
for 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 generation
verification 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, 1973
scala,
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 = 0
dountil(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) <= 'fuelTHEN 150
130 PRINT "You don't have that much fuel"
140 GOTO 100
ogus.me/2009/03/26/baysick-a-scala-dsl-implementing-basic/
..??***8dccollection.foreach(x => doSomething)
‘FOR’ SPECIAL SYNTAX
..??***8dcfor( x <- collection) doSomething
=
..??***8dc
for(x <- fun1 if (x.isGood);
y <- fun2(x) ) yield z(x,y)
=
..??***8dc
fun1.withFilter(_.isGood).
flatMap(x =>
fun2.map(y=>z(x,y)))
..??***8dccollection.foreach(x => doSomething)
‘FOR’ SPECIAL SYNTAX
..??***8dcfor( x <- collection) doSomething
=
..??***8dc
for(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
=
..??***8dc
for(x <- fun1 if (x.isGood);
y <- fun2(x) ) yield z(x,y)
=
..??***8dc
fun1.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
IMPLICIT
implicit def f(x): y
Use x as y
add ‘own’ methods to existing classes
pass context
define 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 competition
map
flatMap — 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 blocking
Implemented 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 ATTENTION
Ruslan Shevchenko <ruslan@shevchenko.kiev.ua>
@rssh1
https://github.com/rssh

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

  • 1.
    JAVA8 / SCALA Differencepoints & innovation streams Ruslan Shevchenko. <ruslan@shevchenko.kiev.ua> https://github.com/rssh @rssh1
  • 2.
    JAVA / SCALA •Java & Scala significantly different • Exists innovations: scala => java & java=>scala • What language I must learn ? • All of them !
  • 3.
    SCALA JAVA8 public classPerson { 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 )
  • 4.
    SCALA JAVA8 public classPerson extends DTOBase { public String firstName; public String lastName; } case class Person ( firstName: String lastName: String )
  • 5.
    SCALA => JAVA Similar: lambda-expressions traits/ default methods collections API with hight-order functions
  • 6.
    LAMBDA EXPRESSIONS list.sort((x,y)-> { intcmp = 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
  • 7.
    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 …………………….
  • 8.
    TRAITS/DEFAULT METHODS trait AsyncInput[T] { defonReceive(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
  • 9.
    TRAITS/DEFAULT METHODS trait LoggedAsyncInput[T] { this:AsyncInput=> override def onReceive(acceptor:T => ()) = super.onReceive(x => { println(s“received:${x}”) acceptor(x) }) } Scala Java aspects ? …
  • 10.
    TRAITS/DEFAULT METHODS trait LoggedAsyncInput[T] { overridedef onReceive(acceptor:T => ()) = super.onReceive(x => { println(s“received:${x}”) acceptor(x) }) } Scala Java aspects ? … trait MyToString { override def toString = s”[${super.toString}]” }
  • 11.
    TRAITS/DEFAULT METHODS Java defaultinterface: dispatch across class/interface hierarchy Scala traits building hierarchy with process of linearization
  • 12.
    STREAMING COLLECTIONS persons.stream().filter( x ->x.firstName.equals(”Jon”) ).collect(Collectors.toList()) persons.filter(_.firstName == “Jon”) Java Scala
  • 13.
    STREAMING COLLECTIONS persons.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.
  • 14.
  • 15.
  • 16.
    SQL ..??***8dc persons.filter(_.firstName === “Jon”) Scala(slick) Java (http://jinq.org) dbStream(em,Person.class).filter( x -> x.firstName.equals(“Jon”) ).list
  • 17.
    SQL (INSIDE ?) persons.filter(_.firstName=== “Jon”).toList Scala (slick) TableQuery[Expr[Person]] Expr[String], Expr[StringConstant] => Expr[Boolean]
  • 18.
    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( .. ) }
  • 19.
    SQL (INSIDE) ..??***8dc Java (http://jinq.org) dbStream(em,Person.class).filter( x-> x.firstName.equals(“Jon”) ).list DbStream<Person> Person => Boolean
  • 20.
    SQL (INSIDE) ..??***8dc Java (http://jinq.org) dbStream(em,Person.class).filter( x-> x.firstName.equals(“Jon”) ).list Person => Boolean for sql generation we need: analyse bytecode symbolic interpretation collect trace generate sql // runtime-only, not very fast
  • 21.
    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 generation verification in compile time
  • 22.
    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
  • 23.
    SAM • SAM-type =Typewith Single Abstract Method • Method require SAM-type => we can pass lambda- expression to one. • In scala: • 2.11 — with -Xexperimental • 2.12 — by default
  • 24.
    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
  • 25.
    SCALA=>JAVA; JAVA=>SCALA • Javause ‘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 ….
  • 26.
    FUTURE EVOLUTION • 2Groups • 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
  • 27.
    CASE CLASSES ..??***8dc case classPerson(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, 1973 scala, kotlin, ceylon, swift
  • 28.
    FUTURE EVOLUTION • essentialdifferent aspect, not present in java: • internal DSL • flexible syntax • call by name • macros • Variance • strong typing • implicit context
  • 29.
    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
  • 30.
    CALL BY NAME ..??***8dc defdountil(cond: =>Boolean)(body: => Unit): Unit = { var quit = false; while(!quit) { body quit = !cond } } First introduced in Algol 68 var x = 0 dountil(x != 10)(x+=1)
  • 31.
    OWN SYNTAX ..??***8dc object Do { defapply(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)
  • 32.
    BASIC DSL:) ..??***8dc object Lunarextends 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) <= 'fuelTHEN 150 130 PRINT "You don't have that much fuel" 140 GOTO 100 ogus.me/2009/03/26/baysick-a-scala-dsl-implementing-basic/
  • 33.
    ..??***8dccollection.foreach(x => doSomething) ‘FOR’SPECIAL SYNTAX ..??***8dcfor( x <- collection) doSomething = ..??***8dc for(x <- fun1 if (x.isGood); y <- fun2(x) ) yield z(x,y) = ..??***8dc fun1.withFilter(_.isGood). flatMap(x => fun2.map(y=>z(x,y)))
  • 34.
    ..??***8dccollection.foreach(x => doSomething) ‘FOR’SPECIAL SYNTAX ..??***8dcfor( x <- collection) doSomething = ..??***8dc for(x <- collection) yield something = ..??***8dccollection.map( x => something)
  • 35.
    ‘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)) …
  • 36.
    ..??***8dccollection.foreach(x => doSomething) ‘FOR’SPECIAL SYNTAX ..??***8dcfor( x <- collection) doSomething = ..??***8dc for(x <- fun1 if (x.isGood); y <- fun2(x) ) yield z(x,y) = ..??***8dc fun1.withFilter(_.isGood). flatMap(x => fun2.map(y=>z(x,y)))
  • 37.
    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
  • 38.
    IMPLICIT implicit def f(x):y Use x as y add ‘own’ methods to existing classes pass context define type-guided expressions
  • 39.
    FUTURE: MONADIC ..??***8dc for( x<- Future{ calculate x }; y <- Future{ calculate y } ) yield x(x,y) Future[T] foreach — do something after competition map flatMap — future composition
  • 40.
    MACROS ..??***8dc object Log { defapply(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) }
  • 41.
    MACROS Reduce boilerplate code Fastcode generation for HPC Deep AST transformations example: async
  • 42.
    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 blocking Implemented as library (without language change) async: T => Future[T ] await: Future[T] =>T
  • 43.
  • 44.
    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
  • 45.
    THANKS FOR ATTENTION RuslanShevchenko <ruslan@shevchenko.kiev.ua> @rssh1 https://github.com/rssh