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 (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)}
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
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
Top Related