Upload
others
View
20
Download
0
Embed Size (px)
Citation preview
GuidoSalvaneschi:introductiontoreactiveprogramming
AnIntroductiontoReactiveProgramming(2)
Prof.GuidoSalvaneschi
GuidoSalvaneschi:introductiontoreactiveprogramming
Outline
• Analysisoflanguagesforreactiveapplications• Detailsofreactiveframeworks• Advancedconversionfunctions• Examplesandexercises• Relatedapproaches
GuidoSalvaneschi:introductiontoreactiveprogramming
• Atransformational system– Acceptsinput,performscomputationonit,producesoutput,andterminates
– Compilers,shelltools,scientificcomputations
• Areactive system– Continuouslyinteractswiththeenvironment– Updatesitsstate
SoftwareTaxonomy
GuidoSalvaneschi:introductiontoreactiveprogramming
HowtoimplementReactiveSystems?
• ObserverPatter– Thetraditional wayinOOlanguages
• Language-levelevents– Event-basedlanguages
• Signals,vars,eventsandtheircombination– Reactivelanguages
GuidoSalvaneschi:introductiontoreactiveprogramming
The(good?old)ObserverPatternbooleanhighTemp;booleansmoke;
voidInit(){tempSensor.register(this);smokeSensor.register(this);
}
voidnotifyTempReading(TempEvente){highTemp=e.getValue()>45;if(highTemp&&smoke){
alert.start();}
}
voidnotifySmokeReading(SmokeEvente){smoke=e.getIntensity()>0.5;if(highTemp&&smoke){
alert.start();}
}
Callbackfunctions
State
Controlstatements
Registration
Callbackfunctions
Controlstatements
GuidoSalvaneschi:introductiontoreactiveprogramming
Observerforchangepropagation
• Mainadvantage:
DecouplethecodethatchangesavalueXfromthecodethatupdatesthevaluesdependingonX
– “Source”doesn’tknowabout“Constraint”
– Temp/Smokesensorsdonotknowaboutfiredetector
GuidoSalvaneschi:introductiontoreactiveprogramming
• Eventsareoftenusedtoenforcedatadependencyconstraints
– booleanhighTemp:=(temp.value>45);
The(good?old)ObserverPattern
GuidoSalvaneschi:introductiontoreactiveprogramming
TheExample:Observertrait Observable{val observers=scala.collection.mutable.Set[Observer]()def registerObserver(o:Observer)={observers+=o}def unregisterObserver(o:Observer)={observers-=o}def notifyObservers(a:Int,b:Int)={observers.foreach(_.notify(a,b))}}trait Observer{def notify(a:Int,b:Int)}
class Sources extends Observable{var a=3var b=7}class Constraint(a:Int,b:Int)extends Observer{var c=a+bdef notify(a:Int,b:Int)={c=a+b}}
val s=new Sources()val c=new Constraint(s.a,s.b)s.registerObserver(c)s.a =4s.notifyObservers(s.a,s.b)s.b =8s.notifyObservers(s.a,s.b)
GuidoSalvaneschi:introductiontoreactiveprogramming
The(good?old)ObserverPattern
Longstoryofcriticism…
• Inversionofnatural dependencyorder– “Sources”updates“Constraint”butinthecode“Constraint”calls“Sources”(toregisteritself)
• Boilerplatecode trait Observable{val observers=scala.collection.mutable.Set[Observer]()def registerObserver(o:Observer)={observers+=o}def unregisterObserver(o:Observer)={observers-=o}
….tempSensor.register(this);smokeSensor.register(this);
GuidoSalvaneschi:introductiontoreactiveprogramming
The(good?old)ObserverPattern
• Reactionsdonotcompose,returnvoid– Howtodefinenewconstraintsbasedontheexistingones
class Constraint(a:Int,b:Int)… {var c=a+bdef notify(a:Int,b:Int)={c=a+b
}}
class Constraint2(d:Int)…{var d=c*7def notify(d:Int)={d=c*7
}}
+ =??
GuidoSalvaneschi:introductiontoreactiveprogramming
The(good?old)ObserverPattern
• Scatteringandtanglingoftriggeringcode
– Failtoupdateallfunctionallydependentvalues.
– Valuesareoftenupdatetoomuch(defensively)
val s=new Sources()val c=new Constraint(s.a,s.b)s.registerObserver(c)s.a =4s.notifyObservers(s.a,s.b)s.b =8s.notifyObservers(s.a,s.b)
change(b)view.update()............
change(a)view.update()..................
..................change(c)view.update()
VIEWA B C
DATAABC
GuidoSalvaneschi:introductiontoreactiveprogramming
The(good?old)ObserverPattern
• Imperativeupdatesofstate
• Noseparationofconcerns
class Constraint(a:Int,b:Int)extends Observer{var c=a+bdef notify(a:Int,b:Int)={c=a+b}}
class Constraint(a:Int,b:Int)extends Observer{var c=a+bdef notify(a:Int,b:Int)={c=a+b}}
Updatelogic+
Constraintdefinition
GuidoSalvaneschi:introductiontoreactiveprogramming
Event-basedLanguages
• Language-levelsupportforevents– C#,Ptolemy,REScala,…
– Imperativeevents
– Declarativeevents,||,&&,map,…
val update=Evt[Unit]()
val changed[Unit]=resized||moved||afterExecSetColorval invalidated[Rectangle]=changed.map(_=>getBounds())
val e=Evt[Int]()e+={println(_)}e(10)
GuidoSalvaneschi:introductiontoreactiveprogramming
Event-basedLanguages
val update=Evt[Unit]()val a=3val b=7val c=a+b//Functionaldependency
update+=(_=>{c=a+b})
a=4update()b=8update()
GuidoSalvaneschi:introductiontoreactiveprogramming
Event-basedLanguages
• Morecomposable– Declarativeeventsarecomposedbyexistingevents(notintheexample)
• Lessboilerplatecode– Applicationsareeasiertounderstand
• GoodintegrationwithObjectsandimperativestyle:– Imperativeupdatesandsideeffects– Inheritance,polymorphism,…
GuidoSalvaneschi:introductiontoreactiveprogramming
Event-basedLanguages
• Dependenciesstillencodedmanually– Handlerregistration
• Updatesmustbeimplementedexplicitly– Inthehandlers
• Notificationsarestillerrorprone:– Toorarely/toooften
class Connector(val start:Figure,val end:Figure){start.changed +=updateStartend.changed +=updateEnd...def updateStart(){...}def updateEnd(){...}…
GuidoSalvaneschi:introductiontoreactiveprogramming
ReactiveLanguages
• Functional-reactiveprogramming(FRP)-- Haskell– Time-changingvaluesasdedicatedlanguageabstractions.
[Functionalreactiveanimation,ElliottandHudak.ICFP’97]
• Morerecently:– FrTime [Embeddingdynamicdataflowinacall-by-valuelanguage,
CooperandKrishnamurthi,ESOP’06]
– Flapjax [Flapjax:aprogramminglanguageforAjaxapplications.Meyerovich etal.OOPSLA’09]
– Scala.React [I.Maier etal,DeprecatingtheObserverPatternwithScala.React.Technicalreport,2012]
GuidoSalvaneschi:introductiontoreactiveprogramming
ReactiveLanguagesandFRP
• Signals– Dedicatedlanguageabstractionsfortime-changing values
• AnalternativetotheObserverpatternandinversionofcontrol
val a=Var(3)val b=Var(7)val c=Signal{a()+b()}
println(c.now)>10a()=4println(c.now)>11
GuidoSalvaneschi:introductiontoreactiveprogramming
title="ReactiveSwingApp"val label=new ReactiveLabelval button=new ReactiveButton
val nClicks =button.clicked.fold(0){(x,_)=>x+1}
label.text =Signal{(if (nClicks()==0)"No"else nClicks())+"buttonclicksregistered"}
button.text =Signal{"Clickme"+(if (nClicks()==0)"!" else "again" )}
contents=new BoxPanel(Orientation.Vertical){contents+=buttoncontents+=label
}
/*Createthegraphics*/title="ReactiveSwingApp“val button=newButton{text="Clickme!"}val label=new Label{text="Nobuttonclicksregistered"}contents=new BoxPanel(Orientation.Vertical){contents+=buttoncontents+=label}
/*Thelogic*/listenTo(button)var nClicks =0reactions+={case ButtonClicked(b)=>nClicks +=1label.text ="Numberofbuttonclicks:"+nClicksif (nClicks >0)button.text ="Clickmeagain"
}
GuidoSalvaneschi:introductiontoreactiveprogramming
ReactiveLanguages• Easiertounderstand
– Declarativestyle– Localreasoning– Noneedtofollowthecontrolflow
toreverseengineertheconstraints• Dependentvaluesareautomaticallyconsistent
– Noboilerplatecode– Noupdateerrors(noupdates/updatedefensively)– Noscatteringandtanglingofupdatecode
• Reactivebehaviorsarecomposable– Incontrasttocallbacks,whichreturnvoid
GuidoSalvaneschi:introductiontoreactiveprogramming
Signalsallowagooddesign.Buttheyarefunctional(only).
Functionalprogrammingisgreat!But…
Thesadstory:– Theworldisevent-based,…– Often imperative,…– AndmostlyObject-oriented
NOW…val a=Var(3)val b=Var(7)val c=Signal{a()+b()}val d=Signal{2*c()}val e =Signal{"Result:" +d()}
GuidoSalvaneschi:introductiontoreactiveprogramming
ReactiveLanguages
• Inpractice,botharesupported:– Signals(continuous)– Events(discrete)
• Conversionfunctions– Bridgesignalsandevents– Allowinteractionwithobjectsstateandimperativecode
Changed :: Signal[T] -> Event[T]Latest :: Event[T] -> Signal[T]
GuidoSalvaneschi:introductiontoreactiveprogramming
Fold
• Createsasignalbyfoldingeventswithafunctionf– Initiallythesignalholdstheinit value.
• fold[T,A](e:Event[T],init:A)(f:(A,T)=>A):Signal[A]
val e=Evt[Int]()val f=(x:Int,y:Int)=>(x+y)val s:Signal[Int]=e.fold(10)(f)assert(s.now ==10)e(1)e(2)assert(s.now ==13)
GuidoSalvaneschi:introductiontoreactiveprogramming
LatestOption
• Variantoflatest.– TheOptiontypeforthecasetheeventdidnotfireyet.– LatestvalueofaneventasSome(value)orNone
• latestOption[T](e:Event[T]):Signal[Option[T]]
val e=Evt[Int]()val s:Signal[Option[Int]]=e.latestOption(e)assert(s.now ==None)e(1)assert(s.now ==Option(1))e(2)assert(s.now ==Option(2))e(1)assert(s.now ==Option(1))
GuidoSalvaneschi:introductiontoreactiveprogramming
Last
• Generalizeslatest– Returnsasignalwhichholdsthelastn events– Initiallyanemptylist
• last[T](e:Event[T],n:Int):Signal[List[T]]
val e=Evt[Int]()val s:Signal[List[Int]]=e.last(5)
assert(s.now ==List())e(1)assert(s.now ==List(1))e(2)assert(s.now ==List(2,1))
e(3);e(4);e(5)assert(s.now ==List(5,4,3,2,1))e(6)assert(s.now ==List(6,5,4,3,2))
GuidoSalvaneschi:introductiontoreactiveprogramming
List
• Collectstheeventvaluesina(evergrowing)list• Usecarefully…potentialmemoryleaks
• list[T](e:Event[T]):Signal[List[T]]
GuidoSalvaneschi:introductiontoreactiveprogramming
Iterate
• Repeatedlyappliesf toavaluewhene occurs– Thereturnsignalisconstant,basedoninit– Fissimilartoahandler
• iterate[A](e:Event[_],init:A)(f:A=>A):Signal[A]
var test:Int =0val e=Evt[Int]()val f=(x:Int)=>{test=x;x+1}val s:Signal[Int]=e.iterate(10)(f)
e(1)assert(test==10)assert(s.now ==10)e(2)assert(test==11)assert(s.now ==10)e(1)assert(test==12)assert(s.now ==10)
GuidoSalvaneschi:introductiontoreactiveprogramming
Count
• Returnsasignalthatcountstheoccurrencesofe– Initially,thesignalholds0.– Theargumentoftheeventisdiscarded.
• count(e:Event[_]):Signal[Int]
val e=Evt[Int]()val s:Signal[Int]=e.countassert(s.now ==0)e(1)e(3)assert(s.now ==2)
GuidoSalvaneschi:introductiontoreactiveprogramming
Snapshot
• Returnsasignalupdatedonlywhene fires.– Otherchangesofs areignored.– Thesignalisupdatedtothecurrentvalueofs.– Returnsthesignalitselfbeforee fires
• snapshot[V](e:Event[_],s:Signal[V]):Signal[V]val e=Evt[Int]()val v=Var(1)val s1=Signal{v()+1}val s=e.snapshot(s1)
assert(s.now ==2)e(1)assert(s.now ==2)v.set(2)//s1==3assert(s.now ==2)e(1)assert(s.now ==3)
s!?
GuidoSalvaneschi:introductiontoreactiveprogramming
Change
• Similartochanged– changed[U]:Event[U]– Providesboththeoldandthenewvalueinatuple– change[U]:Event[Diff[U]]
val s=Signal{...}val e:Event[Diff[Int]]=s.changee+=(x:Diff[Int]=>{val (old,nnew):(Int,Int)=x.pair...
})
GuidoSalvaneschi:introductiontoreactiveprogramming
ChangedTo
• Similartochanged– Theeventisfiredonlyifthesignalholdsthegivenvalue– Thevalueofeisdiscarded
• changedTo[V](value:V):Event[Unit]
var test=0val v=Var(1)val s=Signal{v()+1}val e:Event[Unit]=s.changedTo(3)e+=((x:Unit)=>{test+=1})
assert(test==0)vset2assert(test==1)vset3assert(test==1)
test!?
GuidoSalvaneschi:introductiontoreactiveprogramming
Toggle
• Switchesbetweensignalsontheoccurrenceofe.– Thevalueattachedtotheeventisdiscarded– toggle[T](e:Event[_],a:Signal[T],b:Signal[T]):Signal[T]
val e=Evt[Int]()val v1=Var(1)val s1=Signal{v1()+1}val v2=Var(11)val s2=Signal{v2()+1}val s=e.toggle(s1,s2)
assert(s.now ==2)e(1)assert(s.now ==12)v2.set(12)assert(s.now ==13)v1.set(2)assert(s.now ==13)e(1)v1.set(3)assert(s.now ==4)v2.set(13)assert(s.now ==4)
S!?
GuidoSalvaneschi:introductiontoreactiveprogramming
switchOnce
• Switchestoanewsignalprovidedasaparameteronce,ontheoccurrenceofe
switchOnce[T](e:Event[_],original:Signal[T],newSignal:Signal[T]):Signal[T]
val e=Evt[Int]()val v1=Var(0)val v2=Var(10)val s1=Signal{v1()+1}val s2=Signal{v2()+1}val s3=e.switchOnce(s1,s2)
assert(s3.now==1)v1.set(1)assert(s3.now==2)e(1)assert(s3.now==11)e(2)v2.set(11)assert(s3.now==12)
GuidoSalvaneschi:introductiontoreactiveprogramming
Noteontheinterface
• Weshowedthe“nonOO”signatureformostoftheinterfacefunctions– Inpractice,thesignatureisinOOstyle– Oneoftheparametersisthereceiverofthemethod
• Forexample
– Mustbecalledas:snapshot(e,s)//snapshot[V](e:Event[_],s:Signal[V]):Signal[V]
e.snapshot(s)//e.snapshot[V](s:Signal[V]):Signal[V]
GuidoSalvaneschi:introductiontoreactiveprogramming
Implementation:Challenges
• In-languagereactiveabstractions– DSL/Compiler– Buildthedependencymodel
• Languageruntime– Dependencygraph
• Evaluation• Changepropagation• Modelmaintenance
val e,f,g=Var(1)val d=Var(true)
c=Signal{f()+g()}b=Signal{e()*100}a=Signal{
if(d)celse b
}a
bcd
ef g
GuidoSalvaneschi:introductiontoreactiveprogramming
DSLImplementation
• Buildingthegraph– Var(3)->leaf– Var(4)->leaf– “a()+b()”savedinaclosure– Signal{…}->dependentnode
• Signalexpressionevaluation– Reactivevalues ->edges– Signal=resultoftheevaluation
val a=Var(3)val b=Var(4)val c=Signal{a()+b()}
a
c
b
GuidoSalvaneschi:introductiontoreactiveprogramming
Pullvs.PushModels
f
d
c
a b
y z
h
e
i
g
…
f
d
c
a b
y z
h
e
i
g
…
E.g.,REScala,Rx,bacon.js
GuidoSalvaneschi:introductiontoreactiveprogramming
Temporaryspurious valuesduetopropagationorder.– Updateorderabdc– a()=2b<-4,d<-7,c<-6,d<-10
• Effects:– dredundantlyevaluated2times– Firstvalueofdhasnomeaning– e erroneouslyfiredtwotimes
Glitches
a
b
d
c
val a=Var(1)val b=Signal{a()*2}val c=Signal{a()*3}val d=Signal{b()+c()}val e =d.changed
e
GuidoSalvaneschi:introductiontoreactiveprogramming
• Ensuredbyupdatesintopologicalorder– NodesareassignedtolevelsLn– Levelsareupdatesinorder– E.g.,“abcde”or“acbde”
• Technicalsolutions:– Priorityqueue– Nodeswaitforchildrenbeforeevaluating
GlitchFreedom
a
b
d
c
e
L1
L2
L3
L4
GuidoSalvaneschi:introductiontoreactiveprogramming
• Dependenciesbasedonruntimeconditions
– Incase c==true,dmustchange:• Ifa changes• Notifb changes
– d dependsona orbbasedon currentvalueofc
– Changedependenciesatruntime
Dynamicdependencies
val a=Var(3)val b=Var(7)val c=Var(false)val d=Signal{if c()a()elseb()
}val e =Signal{2*d()}
a b
d
e
c
GuidoSalvaneschi:introductiontoreactiveprogramming
• Easierimplementation• Redundantevaluations– d isexecuteduponbassignments
– eveniftheddoesnotchange
(Lackof)Dynamicdependencies
val a=Var(3)val t=Var(7)val c=Var(true)val d=Signal{if c()a()elseb()
}while(true){b()=…//systemtime}a b
d
e
c
GuidoSalvaneschi:introductiontoreactiveprogramming
• Rejectloops– Responsibilitytotheprogrammer(REScala,Flapjax)– Loopsrejectedbythecompiler
• Acceptloops:whichsemantics?– Delaytothenextpropagationround– Fixpointsemantics
• Timeconsuming?• Termination?
AboutLoops
val x=Signal{y()+1}val y=Signal{x()+1}
GuidoSalvaneschi:introductiontoreactiveprogramming
Example:InterfaceFunctions
• Countmouseclicks
• Betterwithinterfacefunctions
• Evenbetter:usecount!
val click:Event[(Int,Int)]=mouse.clickval nClick:Signal[Int]=click.fold(0)((x,_)=>x+1)
val click:Event[(Int,Int)]=mouse.clickval nClick=Var(0)click+={_=>nClick.transform(_+1) //nClick()=nClick.now +1}
val click:Event[(Int,Int)]=mouse.clickval nClick:Signal[Int]=click.count()
Concisenessvs.
Generality
GuidoSalvaneschi:introductiontoreactiveprogramming
Example:InterfaceFunctions
• Holdthepositionofthelastclickinasignal
• Betterwithinterfacefunctions
val clicked:Event[Unit]=mouse.clickedval position:Signal[(Int,Int)]=mouse.position
val clicked:Event[Unit]=mouse.clickedval position:Signal[(Int,Int)]=mouse.positionvar lastClick =Var(0,0)clicked+={_=>lastClick()=position()}
val lastClick:Signal[(Int,Int)]=positionsnapshotclicked
GuidoSalvaneschi:introductiontoreactiveprogramming
MeanOverWindow
• EventscollectDouble valuesfromasensor• Meanoverashiftingwindowofthelastn events• Printthemeanonlywhenitchanges
e(2)e(1)e(3)e(2)e(1)e(3)e(4)e(1) e(3)e(4)
n
OLD NEW
GuidoSalvaneschi:introductiontoreactiveprogramming
MeanOverWindow• Meanoverashiftingwindowofthelastnevents• Printthemeanonlywhenitchanges
val e=Evt[Double]
val window=e.last(5)valmean=Signal{window().sum/window().length}mean.changed +={println(_)}
e(2);e(1);e(3);e(4);e(1);e(1)
2.01.52.02.52.22.0
GuidoSalvaneschi:introductiontoreactiveprogramming
Example:InterfaceFunctions
/*Composereactivevalues*/valmouseChangePosition =mouseMovedE ||mouseDraggedEvalmousePressedOrReleased =mousePressedE ||mouseReleasedEvalmousePosMoving:Signal[Point]=mouseChangePosition.latest(new Point(0,0))val pressed:Signal[Boolean]=mousePressedOrReleased.toggle(Signal{false },Signal{true })
GuidoSalvaneschi:introductiontoreactiveprogramming
DependencyGraph/*Composereactivevalues*/valmouseChangePosition =mouseMovedE ||mouseDraggedEvalmousePressedOrReleased =mousePressedE ||mouseReleasedEvalmousePosMoving:Signal[Point]=mouseChangePosition.latest(new Point(0,0))val pressed:Signal[Boolean]=mousePressedOrReleased.toggle(Signal{false },Signal{true })
mouseMoved mouseDraggedE
mouseChangePosition
mousePressedE mouseReleasedE
mousePressedOrReleased
mousePosMoving
Signal{false } Signal{true }
pressed
GuidoSalvaneschi:introductiontoreactiveprogramming
Example:TimeElapsing
• Wewanttoshowtheelapsingtimeonadisplay• (second,minute,hour,day)
(0,0,0,0)(1,0,0,0)(2,0,0,0)…(59,0,0,0)(0,1,0,0)(1,1,0,0)(2,1,0,0)…(59,1,0,0)(0,2,0,0)
(1,2,0,0)…(59,59,0,0)(0,0,1,0)…(59,59,23,0)(0,0,0,1)….
GuidoSalvaneschi:introductiontoreactiveprogramming
object TimeElapsing extends App{
println("start!")
val tick=Var(0)val second=valminute=val hour=val day=
while(true){Thread.sleep(0)println((second.now,minute.now,hour.now,day.now))tick.set(tick.now +1)}}
Butdayisstillcircular.Atsomepointday==0again
Also,conceptuallyhardtofollow
TimeElapsing:FirstAttempt
Signal{tick()%60}Signal{tick()/60%60}
Signal{tick()/(60*60)%(60*60)}Signal{tick()/(60*60*24)%(60*60*24)}
GuidoSalvaneschi:introductiontoreactiveprogramming
TimeElapsing
object AdvancedTimeElapsing extends App{println("start!")val tick=Evt[Unit]()
val numTics =val seconds=valminutes=val hours=val days=
while(true){Thread.sleep(0)println((seconds.now,minutes.now,hours.now,days.now))tick(())//tick.fire()}}
tick.countSignal{numTics()%60}Signal{seconds.changedTo(0).count.apply %60}
Signal{minutes.changedTo(0).count.apply %24}hours.changedTo(0).count
Uses.changedTo(v)- Firesandeventifsholdsve.count- Countstheoccurrencesofe
GuidoSalvaneschi:introductiontoreactiveprogramming
Exercise:drawdependencygraph
• Whichvariablesareaffectedbyachangetotick?
tick
numTics
seconds
seconds.changedTo(0)
minutes
minutes.changedTo(0)
hours
hours.changedTo(0)
days
val tick=Evt[Unit]()val numTics =tick.countval seconds=Signal{numTics()%60}valminutes=Signal{seconds.changedTo(0).count()%60}val hours=Signal{minutes.changedTo(0).count()%24}val days=hours.changedTo(0).count
(Somenodesomitted)
GuidoSalvaneschi:introductiontoreactiveprogramming
Example:SmashingParticles
• Particles– Getbigger– Movebottom-right
GuidoSalvaneschi:introductiontoreactiveprogramming
val toDraw =ListBuffer[Function1[Graphics2D,Unit]]()typeDelta=Point
class Oval(center:Signal[Point],radius:Signal[Int]){toDraw +=((g:Graphics2D)=>{g.fillOval(center.now.x,center.now.y,radius.now,radius.now)})
}
val base=Var(0)val time=Signal{base()%200}//timeiscyclic:)
val point1=Signal{new Point(20+time(),20+time())}new Oval(point1,time)val point2=Signal{new Point(40+time(),80+time())}new Oval(point2,time)… override defmain(args:Array[String]){
while (true){frame.repaintThreadsleep20base()=base.now +1
}}
• Signalsareusedinsideobjects!
GuidoSalvaneschi:introductiontoreactiveprogramming
TrainingwithRP- Resources
• Examplesinthelectureslides– Observer– Reactiveprogramming
• Homeworkassignments• REScala examples(online,RPandOOversion)• REScala manual(online)
GuidoSalvaneschi:introductiontoreactiveprogramming
…becomingVeryPopular
List<String>l=Arrays.asList("a1","c2","b1","c2");l.stream().filter(s->s.startsWith("c")).map(String::toUpperCase).sorted().collect(Collectors.toList) getDataFromNetwork()
.skip(10)
.take(5)
.map({s->returns+"transformed"})
.subscribe({println "onNext =>"+it})
TwitterUtils.createStream(...).filter(_.getText.contains("Spark")).countByWindow(Seconds(5))