/
Deprecating the Observer Pattern EPFLREPORT Ingo Maier Deprecating the Observer Pattern EPFLREPORT Ingo Maier

Deprecating the Observer Pattern EPFLREPORT Ingo Maier - PDF document

pamella-moone
pamella-moone . @pamella-moone
Follow
424 views
Uploaded On 2015-05-28

Deprecating the Observer Pattern EPFLREPORT Ingo Maier - PPT Presentation

lastnameepch Abstract Programming interactive systems by means of the observer pattern is hard and errorprone yet is still the implementa tion standard in many production environments We present an approach to gradually deprecate observers in favor o ID: 76036

lastnameepch Abstract Programming interactive systems

Share:

Link:

Embed:

Download Presentation from below link

Download Pdf The PPT/PDF document "Deprecating the Observer Pattern EPFLREP..." is the property of its rightful owner. Permission is granted to download and print the materials on this web site for personal, non-commercial use only, and to display it on your personal computer provided you do not modify the materials and that you retain all copyright notices contained in the materials. By downloading content from our website, you accept the terms of this agreement.


Presentation Transcript

EncapsulationAsthestatevariablepathescapesthescopeoftheobservers,theobserverpatternbreaksencapsula-tion.ComposabilityMultipleobserversformaloosecollectionofobjectsthatdealwithasingleconcern(ormultiple,seenextpoint).Sincemultipleobserversareinstalledatdifferentpointsatdifferenttimes,wecan't,forinstance,easilydisposethemaltogether.SeparationofconcernsTheaboveobserversnotonlytracethemousepathbutalsocalladrawingcommand,ormoregenerally,includetwodifferentconcernsinthesamecodelocation.Itisoftenpreferabletoseparatetheconcernsofconstructingthepathanddisplayingit,e.g.,asinthemodel-view-controller(MVC)[30]pattern.ScalablityWecouldachieveaseparationofconcernsinourexamplebycreatingaclassforpathsthatitselfpublisheseventswhenthepathchanges.Unfortunately,thereisnoguaranteefordataconsistencyintheobserverpattern.Letussupposewewouldcreateanothereventpublishingobjectthatdependsonchangesinouroriginalpath,e.g.,arectanglethatrepresentstheboundsofourpath.Alsoconsideranobserverlisteningtochangesinboththepathanditsboundsinordertodrawaframedpath.Thisobserverwouldmanuallyneedtodeterminewhethertheboundsarealreadyupdatedand,ifnot,deferthedrawingoperation.Otherwisetheusercouldobserveaframeonthescreenthathasthewrongsize(aglitch).UniformityDifferentmethodstoinstalldifferentobserversdecreasecodeuniformity.AbstractionThereisalowlevelofabstractionintheex-ample.Itreliesonaheavyweightinterfaceofacontrolclassthatprovidesmorethanjustspecicmethodstoin-stallmouseeventobservers.Therefore,wecannotab-stractoverthepreciseeventsources.Forinstance,wecouldlettheuserabortadragoperationbyhittingthees-capekeyoruseadifferentpointerdevicesuchasatouchscreenorgraphicstablet.ResourcemanagementAnobserver'slife-timeneedstobemanagedbyclients.Becauseofperformancereasons,wewanttoobservemousemoveeventsonlyduringadragoperation.Therefore,weneedtoexplicitlyinstallanduninstallthemousemoveobserverandweneedtorememberthepointofinstallation(controlabove).SemanticdistanceUltimately,theexampleishardtoun-derstandbecausethecontrolowisinvertedwhichre-sultsintoomuchboilerplatecodethatincreasesthese-manticdistancebetweentheprogrammersintentionandtheactualcode.Mousedragging,whichalreadycomesinlargevarieties,isjustanexampleofthemoregeneralsetofinputges-turerecognition.Ifwefurthergeneralizethistoeventse-quencerecognitionwith(boundedorunbounded)loops,alltheproblemswementionedabovestillremain.Manyex-amplesinuserinterfaceprogrammingarethereforeequallyhardtoimplementwithobservers,suchasselectingasetofitems,steppingthroughaseriesofdialogs,editingandmark-ingtext–essentiallyeveryoperationwheretheusergoesthroughanumberofsteps.1.1ContributionsandOverviewOurcontributionsare:Weshowhowtointegratecomposablereactiveprogram-mingabstractionsintoastaticallytypedprogramminglanguagethatsolvetheproblemsoftheobserverpat-tern.Toourknowledge,Scala.ReactistherstsystemthatprovidesseveralAPIlayersallowingprogrammerstostepwiseportobserver-basedcodetoadata-owpro-grammingmodel.Wedemonstratehowanembedded,extensibledata-owlanguageprovidesthecentralfoundationforacompos-ablevariantofobservers.Itfurtherallowsustoeasilyexpressrst-classeventsandtime-varyingvalueswhoseprecisebehaviorchangeovertime.Theembeddeddata-owlanguagecanmakeuseofthewholerangeofexpressionsfromourhostlanguagewith-outexplicitlifting.WeshowhowthiscanbeachievedbytheuseofdelimitedcontinuationsintheimplementationofourreactiveprogrammingDSL.Inthefollowing,westartwiththestatusquoofhandlingeventswithcallbacksandgraduallyintroduceandextractabstractionsthateventuallyaddressalloftheobserverpat-ternissuesweidentiedabove.Ultimately,wewillarriveatastatewherewemakeefcientuseofobject-oriented,functional,anddata-owprogrammingprinciples.Ourab-stractionstnicelyintoanextensibleinheritancehierarchy,promotetheuseofimmutabledataandletclientsreacttomultipleeventsourceswithoutinversionofcontrol.2.AgeneralinterfaceforcomposableeventsTherststeptosimplifyeventlogicinanapplicationistocomeupwithageneraleventinterfacesothatalleventhandlingcodecanworkwithauniforminterface.Asecondaspecttothisisreusability:ifwecanhideeventpropaga-tionandobserverhandlingbehindageneralinterface,clientscaneasilypublisheventsfortheirowndatastructures.Now,designingsuchageneralinterfaceisaneasytask.Wein-troduceaclassEventSource[A],whichrepresentsgenericeventsources.Wecanuseaneventsourcetoraiseoremiteventsatanytime.TypeparameterAdenotesthetypeaneventfromagivensourcecanhave.Hereishowwecreateaneventsourceofintegersandraiseanumberofevents:vales=newEventSource[Int]esraise1esraise2 streams,e.g.,String.WecanextractquitmessagesfromeachofthemergedeventstreamswiththehelpofthemapcombinatorwhichisdenedintraitEvents:defmap[B](f:A=�B):Events[B]Itreturnsastreamofresultswhichraisesatthesametimeastheoriginalstreambuteacheventappliedtothegivenfunction.Wecannowimplementquitasfollows:valquit=(quitButton.clicks.map(x=�"Ok")mergequitMenu.clicks.map(x=�"Ok")mergefatalExceptions.map(x=�x.getMessage))TherearemanymoreusefulcombinatorsinclassEventsthathavetheirorigininfunctionalreactiveprogramming(FRP)[13,21,48].AsomewhatScalaspecicconveniencecombinatorisdefcollect[B](p:PartialFunction[A,B]):Events[B]whichmapsandltersatthesametime.Theresultingeventstreamraisesthoseeventsfromtheoriginalstreamappliedtothegivenpartialfunctionpforwhichpisdened.Themapandfiltercombinatorscanbothbeimple-mentedintermsofcollect:defmap[B](f:A=�B):Events[B]=collect{casex=�f(x)}deffilter(p:A=�Boolean):Events[A]=collect{casexifp(x)=�x}3.Reactors:composableobserverswithoutinversionofcontrolUsingourneweventabstraction,wecannowdeneaclassControlthatexposesmouseeventsaseventstreams.Ourinitialmousedraggingexamplebecomes:varpath:Path=nullvarmoveObserver=nullobserve(control.mouseDown){event=�path=newPath(event.position)moveObserver=observe(control.mouseMoves){event=�path.lineTo(event.position)draw(path)}}observe(control.mouseUp){event=�moveObserver.dispose()path.close()draw(path)}Sincewehaveauniformobservemechanismandrst-classevents,wecanabstractovertheeventsinvolvedinadragoperation.Wecould,forexample,wraptheaboveinafunctionwiththefollowingsignature:definstallDragController(start:Events[Positional],move:Events[Positional],end:Events[Positional])andletmouseeventsextendthePositionalinterfacewithapositionmember.Now,wecouldletusersperformdragoperationswithadifferentpointerdeviceandstartorabortwithkeycommands.Forexample:definstallDragController(pen.down,pen.moves,pen.upmergeescapeKeyDown.map(x=�pen.position.now))Yet,themostimportantissuethatmakestheabovecodehardtounderstandstillremains:itscontrolowisinverted.Ideally,wewouldwanttodirectlyencodeastatemachinewhichcanbedescribedinformallyasfollows:1.Startanewpath,oncethemousebuttonispressed2.Untilthemouseisreleased,logallmousemovesaslinesinthepath3.Oncethemousebuttonisreleased,closethepathInordertobeabletoturntheabovestepsintocodethatisconceptuallysimilar,weneedtondawaytoletclientspullvaluesfromeventstreamswithoutblockingthecurrentthread.InScala.React,wecanachievethiswithareactorandthenextoperatorwhichispartofanembeddeddata-owlanguage.Thefollowingcreatesareactorthatimple-mentsourrunningexamplewithoutinversionofcontrol.Reactor.once{self=�//step1:valpath=newPath((selfnextmouseDown).position)//step2:selfloopUntilmouseUp{valm=selfnextmouseMovepath.lineTo(m.position)draw(path)}//step3:path.close()draw(path)}ObjectReactordenesthetwomethodsdefonce(body:Reactor=�Unit):Reactordefloop(body:Reactor=�Unit):Reactorthatclientscanusetocreateareactorthatexecutesitsbodyonceorrepeatedly.Theactualbodyofareactorisgivenasanargumenttothesemethods.Formally,abodyisafunctionthatacceptsthereactorunderconstructionasanargument(aselfreferencesimilartoJava'sandScala'sbuilt-inthis)andevaluatestoUnit,i.e.,weareinterestedintheside-effectsofthebody,nottheresultitevaluatesto.Thebodyusesthegivenselfreferencetoexpressanembeddeddata-owprogram.ClassReactorcontainstwocoredata-owmethods:defnext[A](e:Events[A]):Adefdelay:UnitMethodnextsimplysuspendsthecurrentreactoruntilthegiveneventstreamemitsavalue.Oncethestreamraises owlanguageweknowfromreactors.Insteadofperformingside-effects,webuildadata-owsignal:valpath:Signal[Path]=Val(newPath)once{self=�importself._valdown=next(mouseDown)emit(previous.moveTo(down.position))loopUntil(mouseUp){valm=next(mouseMove)emit(previous.lineTo(m.position))}emit(previous.close)}Methodsonceandloop,asweknowthemfromreactorsaresimilarlydenedforsignals.Insteadofcreatingareac-tor,theycreateanewsignalandarecalledonasignalthatdeliverstheinitialvaluesforthenewsignal.Intheexampleabove,wecreateasignalthatstartswithanemptypathandthenproceedsoncethroughthegivendata-owbody.Argu-mentselfreferstothesignalunderconstructionandisoftypeDataflowSignal[Path]whichextendsSignal[Path]anddenesasetofdata-owmethodsinadditiontothoseavailableforreactors.Tokeepthingsshort,werstimportallmembersfromourselfreferencewhichletsusdroptheselfprexes.Wereplacedallpathmutationsanddraw-ingcallsbycallstodata-owmethodemit,whichchangestheresultingpathsignalimmediately.WerefertomethodpreviousinDataflowSignalinordertoobtaintheprevi-ousvalueofourpathsignalandmodifyitssegments.WeareusinganimmutablePathclassabove.MethodslineToandclosedonotmutatetheexistinginstance,butreturnanewpathinstancewhichextendsorclosesthepreviousone.Wecannowimplementthedrawingoperationinasimpleexternalobserver:observe(path)(draw)5.1Adata-owlanguageWehavenowtwovariantsofadata-owlanguage,oneforreactorsandoneforsignals.Inordertokeeplanguagesconsistentandextractcommonfunctionality,wecanfactorourexistingabstractionsintoaclasshierarchyasfollows.traitReactive[+Msg,+Now]{defcurrent(dep:Dependant):Nowdefmessage(dep:Dependant):Option[Msg]defnow:Now=current(Dependent.Nil)defmsg:Msg=message(Dependent.Nil)}traitSignal[+A]extendsReactive[A,A]traitEvents[+A]extendsReactive[A,Unit]ClassesSignalandEventsshareacommonbasetraitReactive.Wewillthereforecollectivelyrefertothemasreactivesinthefollowing.TraitReactivedeclarestwotypeparameters:oneforthemessagetypeaninstanceemitsandoneforthevaluesitholds.Fornow,wehavesubclasssignalwhichemitsitsvalueaschangemessages,andthereforeitsmessageandvaluetypesareidentical.SubclassEventonlyemitsmessagesandneverholdsanyvalue.ItsvaluetypeishenceUnit.SubclassesoftraitReactiveneedtoimplementtwomethodswhichobtainthereactive'scurrentmessageorvalueandcreatedependenciesinasingleturn.Inordertobuildadata-owreactiveusingtheloopandoncecombinators,weimplicitlyconvertareactivetoanintermediateclassthatprovidesthosecombinators2:implicitdefeventsToDataflow[A](e:Events[A])=newEventsToDataflow(e)implicitdefsignalToDataflow[A](s:Signal[A])=newSignalToDataflow(s)Theseintermediateclassesaredenedasfollows:traitReactiveToDataflow[M,N,R:Reactive[M,N],DR:DataflowReactive[M,N,R]]extendsReactive[M,N]{protecteddefinit:Rdefloop(body:DR=℀Unit):Rdefonce(body:DR=℀Unit):R}classEventsToDataflow[A](initial:Events[A])extendsEvents[A]withReactiveToDataflow[A,Unit,Events[A],DataflowEvents[A]]classSignalToDataflow[A](initial:Signal[A])extendsSignal[A]withReactiveToDataflow[A,A,Signal[A],DataflowSignal[A]]TraitReactiveToDataflowextendsReactiveandpro-videstwoadditionaltypeparameterstoxtheprecisetypeofreactiveswearecreating.Thetyperelateddetailsofthisdesignareoutofthescopeofthispaper.ItisaresultfromourexperiencewegatheredduringtheredesignofScala'scollectionlibrarywhichisthoroughlydescribedin[41].Thebasetypefordata-owreactivesdenesthedata-owlanguageforreactivesandisspeciedasfollows:traitDataflowReactive[M,N,R:Reactive[M,N]]extendsReactive[M,N]{defemit(m:M):UnitdefswitchTo(r:R):Unitdefdelay:Unitdefnext[B](r:Reactive[B,_]):BdefnextVal[B](r:Reactive[_,B]):B} 2ThisissimilartoextensionmethodsinLINQ[46]butkeptoutsideoftraitReactiveforadifferentreason:toxtheconcretetypeofdata-owreactivesloopandoncecreatewhilestillallowingcovariantMsgandNowtypeparameters. signaloreventthatiscurrentlyheldbytheoutersignal.Theycanbeimplementedasfollows:defflattenEvents[B](implicitwitness:A=�Events[B])=Events.loop[B]{selfswitchTowitness(selfnextthis)}defflatten[B](implicitwitness:A=�Signal[B])=witness(this.now)loop{self=�selfswitchTowitness(selfnextthis)}Thesecanbegeneralizedintoasinglegenericcombinator.FlatteningasignalofreactivesmakessenseforanysubclassofReactive,notjustSignalorEvents.defflatten[M,N,R:Reactive[M,N],DR:DataflowReactive[M,N,R]](implicitc:A=℀RwithReactiveToDataflow[M,N,R,DR]):R=c(now)loop{self=℀selfswitchToc(selfnextthis)}TheimplicitparameterisusedtoconvertacurrentsignalvaluetoaReactiveToDataflowinordertoconstructadata-owreactive.ThisenablesustoattenasignalofanysubtypeRofReactivetoaninstanceofRthatbehaveslikethereactivethatiscurrentlyheldbythesignal.WewilllaterseehowtomeaningfullyextendtraitReactive.5.3Combinatorsversusdata-owoperationsAsanalternativetoadata-owformulationofthedraggingproblem,wecanwriteitinapurelycombinator-basedstyle.Asimilarexamplecanbefoundin[35],whichweadopttoScala.Reactinthefollowing.valmoves=mouseDownmap{md=℀mouseMovemap(mm=℀newDrag(mm))}valdrops=mouseUpmap{mu=℀Events.Now(newDrop(mu))}valdrags=(movesmergedrops).flattenAbove,weuseourpreviouslydenedflattencombinatortoswitchbetweendifferenteventstreams.Forthisreason,flattenissometimescalledswitch.Infact,ourswitchcombinatorfromaboveisasimpleformofflatten.Theaboveexampleisactuallyaninstanceofamoregen-eralproblem:eventpartitioning.Eventpartitioningdealswiththetaskofconstructingeventstreamsthatdependondifferentstreamsatdifferenttimeperiods.Above,ourre-sultingdragsstreamloopsoverthreepartitions.1.Itremainssilentuntilthenextmousedownevent.2.Betweenmousedownandmouseupevents,itdependsonmousemoveevents,3.Afterthemouseupevent,itraisesanaldropevent.Onewaytodealwitheventpartitioningistobuildahigherordereventstreamasaboveandswitchbetweendif-ferenteventstreamswiththeflattencombinator.Usefulinstrumentsinourcombinatortoolboxarenestingmapappli-cationstocreatehigher-ordereventstreamsandtheasym-metricmergecombinatortoswitchbetween(overlapping)eventstreams.Ourdata-owformulationofthesameproblemisequiv-alentbutavoidsdealingwithhigherordereventstreams.Whereasthehigherordereventstreamdenesthestatetran-sitionofastatemachineasanesteddatastructure,adata-owprogramdescribesitasaatprogramsource.Combinatorsanddata-owreactivescannaturallycom-plementeachother.Forinstance,theimplementationofdata-owmethodloopUntilintraitDataflowBaseisadata-owprogramwhichreusestheswitchcombinator:defloopUntil[A](es:Events[A])(body:=℀Unit):A={valx=esswitch(None,Some(es.msg.get))while(x.now==None){body}x.now.get}5.4RecursionDataowreactivecanbeusedtodenerecursivesignalsandevents.Considerthefollowingsignal:valcounter=0loop{self=℀selfemit(self.now+1)}Thissignalisill-denedandwillthrowanexceptionbecausewearereferringtothecurrentvalueofthesignalwhileevaluatingitscurrentvalue!WethereforedenemethodpreviousinDataflowSignal,whichletusaccesstheoldvalueofthesignalunderconstruction:valcounter=0loop{self=℀selfemit(self.previous+1)}Thissignaliswell-denedbecauseemitstatementsintro-duceadelay.Otherwisetheresultingsignalwouldloopfor-ever.Therefore,delaysintroducedbyemitandswitchTohaveasafetyaspecttotheminthattheypreventloopsfromloopinginnitively.Notethattheabovesignalinfactin-spectsthebehaviorofthereactivescheduler:itcountsprop-agationcyclesstartingwiththecurrentone.Wecould,e.g.,useittoimplementaframeratesignalthatupdatesitsvalueeverysecond:valframeRate=Val(0)loop{self=℀valc0=counter.nowselfnextClock.inSeconds(1)selfemit(counter.now-c0)} Ifxandyareintegersignalsandoneholdsthevalue0,changingtheotherdoesnotchangethevalueofsignalsum.Memberaccessisanothercase:ifsignalpholdspointswithxandycoordinates,changingp'svaluedoesnotautomati-callychangethevalueofcoord.Dependingofthedepthofadependencygraphandthelocationofnon-injectiveexpres-sions,theabovepropagationschemecanbecomeveryinef-cient.Foranexamplethatconveysthebigpictureandthatisnotsomepathologicalcase,consideratreestructuresuchasacontrolhierarchyoradocumentobjectmodel(DOM)inaGUIapplication.Itisrelativelycommontopropagatesomedatafromtheroottotheleafsandpossiblybackagain.AnexamplearevisualattributessuchasCSSstylesthatcontrolsorDOMnodesinheritfromtheirparent.Inthefollowingexample,weaggregateseveralstyleattributesintoanim-mutablePenclass.Theboundsofatreenodethatdisplaysgeometricshapesdependsonitsparentpen'slinewidthat-tribute.classPen(color:Color,lineWidth:Int,cap:CapStyle)traitGeometryNodeextendsNode{defshape:Signal[Shape]valbounds=Signal{f(shape.bounds,parent().pen().lineWidth)}}traitGroupextendsNode{valbounds=children.foldLeft(Rectangle.Nil){(a,b)=�(aunionb).bounds}}Wecannowbuildadeepdependencygraphwithalongpathfromtheroot'sPenattributedowntotheboundsattributesofeachgeometrynodeandupagainfortheboundsofeachgroupnode.Changingthepenoftherootnodewilltriggeraboundscalculationformostofthetree,nomatterwhetherthelinewidthattributeofthenewpenisdifferentfromtheold.6.2Push-drivenImplementationOurcurrentimplementationovercomestheinefcienciesofourrstimplementationwithapurelypush-basedpropaga-tionapproach.Inordertopreventreactivesfromobservinginconsistentdata(alsocalledglitches)duringandbetweenpropagationcycles,wekeepthedependencygraphtopolog-icallysorted.Todoso,weassigneachreactivealevelinthedependencygraph.Allsourcereactiveshavealevelof0,andeverydependentreactivehasthelevelofitshighestdependencyplus1.Apropagationcycleproceedsasfollows.1.Enterallmodied/emittingreactivesintoapriorityqueuewiththeprioritiesbeingthereactives'levels.2.Whilethequeueisnotempty,takethereactiveonthelowestlevelandvalidateitsvalueandmessage.Thereactivedecideswhetheritpropagatesamessagetoitsdependents.Ifitdoesso,itsdependentsareaddedtothepriorityqueueaswell.Thelaststepsolvesourpropagationcappingproblemfromabove.Asignalwhichevaluatestothesamevalueasbefore,e.g.,wouldnotpropagateachangemessageduringthecur-rentcycle.Foradependencygraphwithaxedtopology,i.e.,wherethelevelofreactivesneverchange,thissimplealgorithmissufcienttoavoiddatainconsistencies.Wedo,however,needtodealwithconditionals,branches,andloopsinsignalexpressionsandinparticulardata-owreactivesthatcandroppreviousdependenciesandestablishnewonesfromonepropagationcycletothenext.6.2.1DynamicDependenciesConsiderthefollowingexample:valx=Var(2)//level0valy=Cache{f(x())}//level1valz=Cache{g(y())}//level2valresult=Signal{if(x()==2)y()elsez()}//level2or3Dependingonthecurrentvalueofsignalx,signalresultcanhaveatopologicallevelof2or3.Themostefcientso-lutionwouldbetoalwaysassigntoasignalalevelthatishigherthanalllevelsofitspotentialdependencies–with-outevaluatingthesignalexpression.Unfortunately,thedy-namicsofreactivedependenciesisatoddswithitselfatthistime.Ingeneral,wecanneitherstaticallydetermineallpos-sibledependenciesnorallpossiblelevelsofanexpressionsignal.Therefore,wecannotknowthelevelofaninvalidsig-nalbeforeweactuallyevaluateitscurrentvalue.Theprevi-ouslyknownlevelofareactivemerelyservesasareferencevalueintheinvalidationphase.Ifthelevelturnsoutgreaterthanthepreviousone,weabortthecurrentevaluationbythrowinganexception,assignahigherleveltotheaffectedsignalandrescheduleitforvalidationonahigherlevelinthesamepropagationcycle.Becauseofthispotentialforredundantcomputation,programmersareadvisedtomoveexpensivecomputationsuntilafterreferencingareactive'sdynamicdependencies.Fortunatelythough,manycombina-torshaveenoughinformationtopredictthepreciseleveloftheresultingreactiveandwillthusneverabortduringeval-uation.Moreover,signalsanddata-owreactivestypically"warmup"duringtheirrstiterationanddonotneedtobeabortedinfuturepropagationcycles.Notethatabortingtheevaluationofareactiveisonlysafebecausewedisallowside-effectsinsignalexpressionsandreactivecombinatorarguments.Reactors,however,are shift{(k:A=�Unit)=�continue={()=�mayAbort{op(k)}}continue()}defcontinueLater(k:=�Unit)={continue={()=�k}enginenextTurnthis}MethodcontinueNowacceptsafunctionopwhichtakesthecurrentcontinuationasanargument.Acalltoshift,whichispartoftheScalastandardlibrary,capturesthecurrentcontinuationk,transformsitbyapplyingoptoitandstorestheresultinavariableforimmediateandlateruse.ThetransformedcontinuationiswrappedinacalltomayAbort,whichproperlyabortsandreschedulesthecurrentevaluationifthetopologicallevelofanyaccessedreactiveishigherorequaltothecurrentlevel.MethodcontinueLatercapturesagivencontinuationinavariableandschedulesthisreactiveforthenextturn.Whenvalidatedduringapropagationcycle,adata-owreactivesimplyrunsitscurrentcontinuationsavedinvari-ablecontinue,whichinitiallystartsexecutingthewholebodyofthereactive.Inordertoofferlibraryclientsacompletelytransparentdata-owlanguagethatletthemreuseanyexistingkindofScalaexpression,weextendedourCPStransformimple-mentationtocorrectlydealwithloopsandexceptions.WerefertoAppendixAforthedetails.Wecouldusecontinuationsforsignalexpressionsaswell.Whendiscoveringalevelmismatch,insteadofabortingandreschedulingtheentireevaluationofthesignal,wewouldreschedulejustthecontinuationoftheaffectedsignalandreusetheresultofthecomputationuntilthelevelmismatchwasdiscovered,capturedinthecontinuationclosure.Un-fortunately,thisapproachisratherheavyweight(thoughlessheavyweightthanusingblockingthreads)onaruntimewith-outnativeCPSsupport.Wethereforedonotcurrentlyimple-mentitandleaveitforfutureworktocomparetheoutcomewithourcurrentimplementation.Weareparticularlyinter-estedinhowoftenoneactuallyneedstoabortinrealisticreactiveapplications,whethertheperformanceoverheadofCPSjustiesitsusageinthiscontextincontrasttothemem-oryoverheadoftheclosurescreatedbyourCPStransform.6.5Side-effectsLocalside-effectsareallowedinanysignalexpressionorreactivecombinatorargumentsuchastheEvents.mapfunc-tionargumentoradata-owbody.Localinthiscontextreferstoside-effectsthatdonotescapethescopeofthecom-binatorargumentsuchasthetakecombinatorimplementa-tioninSection5.Wedisallownon-localside-effectssincetheevaluationofareactivecanabortbecauseandretriedonahigherlevelinthesamepropagationcycle.Thefollowingsignalcanthereforeincreasecounteritwicewhenthelevelofthegivensignalsigchanges:defcountChanges(sig:Signal[Any])={vali=0Signal{sig();i+=1;i}}Whenabortingasignalevaluation,theentiresignalexpres-sionisreevaluated,workingwithafreshsetoflocalvari-ablesthatarenotaffectedbypreviousruns.Fordata-owre-actives,however,thesituationisslightlymorecomplicated.Astheysimulatestatemachines,wewanttokeeptheirstatefromoneevaluationtothenext.Areevaluationshouldthere-forenotexecuteanyside-effectingexpressiontwice.Ween-surethatthisisindeedthecasebyalwayscapturingthecur-rentcontinuationbeforealevelmismatchcanhappen.Sincealevelmismatchcanhappenonlyduringacalltonext,switchTo,message,ornow,andsincethesemethodsdonotperformside-effectsthataffectthestateofadata-owre-activebeforealevelmismatchabortioncanhappened,con-tinuingwiththecapturedcontinuationafteranabortionen-suresthatwedonotevaluateside-effectingexpressionsre-dundantly.Internalorexternalside-effectsinreactorsarenotprob-lematic,sincereactorsalwayshavemaximumlevel,i.e.,theirevaluationneveraborts.6.6Avoidingmemoryleaksinlow-levelobserversInternally,Scala.React'schangepropagationisimplementedwithobservers.WedoexposethemtoclientsasaverylightweightwaytoreacttochangesinareactiveaswehaveseeninSection2.Steppingbackforamoment,onemightbetemptedtoimplementaforeachmethodinEventsorevenReactiveanduseitasfollows:classView[A](events:Events[A]){eventsforeachprintln}ThiscaneasilyleadtoareferencepatternasdepictedinFigure1. Figure1.Commonreferencepatterninthestandardob-serverscenario.Thecriticalreferencehereisthearcfromtheeventstreamtotheobserver,whichpreventstheobjectontherighttobedisposedasusual.InalanguagethatreliesonruntimegarbagecollectionsuchasScala,wegenerallyexpectob-jectstobedisposedoncewedon'tholdastrongreferencetothemanymore.Intheabovescenario,however,wehaveastrongreferencepathfromtheeventsourcetotheobservingobject.Foreveryobservingobjectthatwewanttodispose beforethereactiveobject,wewouldneedtoremembertocallanexplicitdisposalmethodthatunsubscribestheob-servingobject'sobservers,otherwisethegarbagecollectorcannotreclaimit.ThereferencepatterninFigure2eliminatestheleakpotential. Figure2.ObserverreferencepatternthateliminatesthememoryleakpotentialofthestandardscenariofromFig-ure1.Notetheweakreferencefromtheeventsourcetotheob-server,depictedbyadashedarc.Iteliminatesanystrongreferencecyclesbetweentheobservingandthepublishingside.Inordertopreventtheobserverfrombeingreclaimedtooearly,wealsoneedastrongreferencefromtheobservingobjecttotheobserver.Itisimportantthatwearealwaysableforcetheprogrammerintocreatingthelatterstrongrefer-ence,otherwisewehaven'tgainedmuch.Insteadofremem-beringthatsheneedstocalladisposemethod,shewouldnowneedtoremembertocreateanadditionalreference.For-tunately,wecanuseScala'straitstoachieveourdesiredref-erencepatternwhilereducingtheburdenoftheprogrammer.Thefollowingtraitneedstobemixedinbyobjectsthatwanttoobserveevents.APIclientshavenootherpossibilitytosubscribeobservers.5traitObserving{privatevalobRefs=newListBuffer[Observer]()abstractclassPersistentObextendsObserver{obRefs+=this}protecteddefobserve(e:Events[A])(op:A=�Unit)=e.subscribe(newPersistentOb{defreceive(){op(emessagethis)}})}Insteadofusingaforeachmethod,wecannowwritethefollowing:classView[A](events:Events[A])extendsObserving{observe(events){x=�println(x)}}AninstanceofclassViewwillprintallarrivingeventsandcannowbeautomaticallycollectedbythegarbagecollec-tor,independentlyfromthegiveneventstreamandwithoutmanuallyuninstallingitsobserver. 5Wecandirectlystoretherstallocatedpersistentobserverinareferenceeld.OnlyforthelesscommoncaseofmultiplepersistentobserversperObservinginstancewedoallocatealiststructuretokeepobserverreferencesaround.Thissavesafewmachinewordsforcommoncases.7.RelatedWorkSomeproductionsystems,suchasSwingandothercompo-nentsoftheJavastandardlibraries,closelyfollowtheob-serverpatternasformalizedin[25].OtherssuchasQtandC#gofurtherandintegrateuniformeventabstractionsaslanguageextensions[32,40,47].F#additionallyprovidesrst-classeventsthatcanbecomposedthroughcombinators.TheRx.NetframeworkcanliftC#language-leveleventstorst-classeventobjects(calledIObservables)andprovidesFRP-likereactivityasaLINQlibrary[36,46].Itsprecisesemantics,e.g.whetherglitchescanoccur,ispresentlyun-cleartous.SystemssuchasJavaFX[42],AdobeFlex[2]orJFaceDataBinding[45]providewhatwecategorizeasreactivedatabinding:avariablecanbeboundtoanexpres-sionthatevaluatestotheresultofthatexpressionuntilitisrebound.Ingeneral,reactivedatabindingsystemsareprag-maticapproachesthatusuallytradedataconsistencyguar-antees(glitches)andrst-classreactivesforaprogrammingmodelthatintegrateswithexistingAPIs.Flexallowsem-beddedActionscript[37]insideXMLexpressionstocreatedatabindings.JavaFX'suseofreactivityistightlyintegratedintothelanguageandtransparentinthatordinaryobjectat-tributescanbeboundtoexpressions.SimilartoScala.React,JFaceDataBindingestablishessignaldependenciesthroughthreadlocalvariablesbutJava'slackofclosuresleadstoamoreverbosedatabindingsyntax.JFaceistargetedtowardsGUIprogrammingandsupportsdatavalidationandinte-grateswiththeunderlyingStandardWidgetToolkit(SWT).7.1FunctionalReactiveProgrammingScala.React'scomposablesignalsandeventstreamsorigi-nateinfunctionalreactiveprogramming(FRP)whichgoesbacktoConalElliot'sFran[21].Itsconceptshavesincebeenadoptedbyavarietyofimplementationswithdifferentpro-gramminginterfacesandevaluationmodels.Theyallhaveincommonthattheyprovideacombinator-basedapproachreactiveprogramming.Franintegratesgeneralideasfromsynchronousdata-owlanguages[27]intothenon-strict,purefunctionallanguageHaskell.Ittakesamonadicapproachandencapsulatesoper-ationsovertime-varyingvalues(calledbehaviorsinFran)anddiscreteeventsintodatastructuresthatareevaluatedbyaninterpreterloop.MostofScala.React'scombinatorsmethodsinEventsandSignaloriginatefromFran.Fran'sevaluationmodelispull-based,i.e.,reactivesarecontinu-ouslysampled.Anevaluationcyclehenceconsistsofsim-plenestedfunctioncalls.In[19],Fran-styleFRPwasre-visedtotintoHaskell'sstandardtypeclassessuchasMonadandFunctor.ItfurthermoreremovesinefcienciesrelatedtoFran'spurelypull-basedevaluation.Itwouldbeveryin-terestingtondperformancecomparisonstoFranandotherHaskell-basedsystems.Fran'sexplicitnotionoftimeandreactivesanditsstream-basedimplementationcouldleadtospace-timeleaksinFRP programs[20].Inordertoovercomethepotentialofleakingreactives,YampaforHaskell[15,39]providesarstclassnotionofsignalfunctionsbasedonarrows[29],ageneral-izationofmonads.Thisleadstoaprogrammingstylecon-ceptuallyclosetodesigningelectriccircuitdiagrams.FranandYampapromoteapurelyfunctional,combinator-basedprogrammingstyle.Yampa,likeFran,ispull-basedandeval-uatesreactivesinrecursivefunctioncalls.FrTime[12,13]integratesFRP-stylereactivityintothestrict,impure,dynamicallytypedfunctionallanguageScheme.Scala.React'spropagationmodeloriginatesinFrTimewhichalsousesapush-drivenevaluationmodelutilizingatopo-logicallyordereddependencygraph.LikeinScala.React,redundantevaluationisavoidedbothinbreadthsinceFr-Timepropagateseventsonlytodependentsofinvalidreac-tivesandindepth,sincepropagationiscappedwhenreach-ingnon-injectivesignaloperationsandeventlters.FrTimereliesonScheme'smacrosystemtoachieveconcisesignalcompositionsyntaxwithnoneedtoadaptexistingdatastruc-turesandoperationstoFrTime.Asaconsequence,abinaryexpressionoversignals(calledbehaviorsinFrTime),e.g.,createsanewsignal.Thismakesthesystemformallyveryelegantbutoriginallycouldleadtolargedependencygraphs.Theseissueshavebeenaddressedin[8],whichsuccessfullyappliesdeforestation-liketechniquestoFrTimeprograms.Scala.React'sapproachusingthreadlocalvariablesforsig-nalexpressionsissimilarinspiritasitavoidsstoringcontin-uationsforeachsignalaccess.Flapjax[35]isalibraryandcompilerforFRP-likere-activityforwebprogramminginJavascriptandevolvedoutofFrTime.Flapjaxcomeswithacompilertoallowconcisesignalexpressions.Whenusedasalibrary,itre-liesonexplicitliftingofreactivesandisthensyntacticallymoreheavyweightbutintegrateswellintoJavaScript.Likeourapproach,Flapjaxintegratesreactiveprogramminginanobject-orientedlanguage.IncontrasttoScala,Flapjax/-Javascriptisdynamicallytyped,i.e.,expressionswhichcanbestaticallyrejectedbyScala.Reactcanleadtodelayedrun-timeerrorsinFlapjaxasdemonstratedin[35].Frappé[14]isanFRPimplementationforJavaandusesamixedpush-pullimplementation.SimilartoJFace,itssyntaxisverbosebecauseofJava'slackofclosuresandgenericsbythetimeitwaswritten.BeingbasedonBeanPropertiesitintegrateswiththeJavastandardlibraryandthussupportsobservers.SuperGlue[34]isadeclarativeobject-orientedcompo-nentlanguagethatsupportsasignalconceptsimilartothatfoundinFRPandScala.React.Forsignalconnections,Su-perGluefollowsauniqueapproachthatwendisclosertoconstraintprogrammingsuchasintheKaleidoscopelan-guagefamily[24]thantoacombinator-ordata-ow-basedapproach.SuperGlueprovidesguardedconnectionrulesandruleoverridingwhichisasimpleformofKaleidoscope'sconstrainthierarchies[7].Itspropagationmodelissimilartoourpreviousnon-strictmodel.7.2AdaptiveFunctionalProgrammingAdaptivefunctionalprogramming(AFP)[1]isanapproachtoincrementalcomputationinML.ItisrelatedtoFRPandScala.Reactsinceitalsocapturescomputationforre-peatedreevaluationinagraph.AFPhasbeenimplementedinHaskell[9]usingmonads.OurCPS-basedrepresenta-tionofdata-owprogramsisrelatedtothiseffortandothermonadicFRPimplementationsbecauseanyexpressiblemonadhasanequivalentformulationincontinuationpassingstyle[22,23].TheAFPdependencygraphandpropagationalgorithmsaremoreelaboratethanScala.React's.ThisismostlyduetoAFP'ssupportforcomputationoverincre-mentallychangingdatastructures.Incontrast,Scala.ReactandFRPcurrentlysupportsreactivitymostlyforplainval-ues.Ourefforttotsignals,eventstreams,andcollectionssuchasourreactivepathstructureintoastandardreactivehi-erarchywithincrementalchangemessagestriestoapproachtheexpressivenessofAFP.7.3DataowProgrammingOurbuilt-indata-owlanguageismostlyinspiredbysyn-chronousdata-owlanguagessuchasSignal[5],Lus-tre[26],andEsterel[6].UnlikeScala.React,theselanguagesusuallyprovidestrongguaranteesonmemoryandtimere-quirementsandarecompiledtostatemachines.Asatrade-offandincontrasttooursystem,mostsynchronousdata-owlanguagesarerst-order,i.e.,theydistinguishbetweenstreamprocessingfunctions,streams,andvaluesthatcanbecarriedoverstreams.Worktowardsahigher-ordersyn-chronousdata-owlanguagecanbefoundin[11].7.4ComplexEventProcessingData-owreactivessharecertaincharacteristicswithcom-plexeventprocessing(CEP)systemssuchasTelegraphCQ[10],SASE[49],andCayuga[18].ThesesystemsusecustomquerylanguagessimilartoSQL[17]torecognizeeventpat-ternsfrommultiplesources.Queriesareusuallystateful,similartoreactorsanddata-owreactives,butarenotde-signedtoperformexternalside-effects.CEPsystemsareoptimizedtohandlelargedatastreamsefcientlywhileourimplementationistargetedtowardsgeneralpurposeeventsystemswheretheamountofeventdataiscomparativelysmall.7.5ActorsData-owreactivesandreactorssharecertainsimilaritieswithactors[3,28],whichareusedasconcurrencyabstrac-tions.Actorsusuallyrunconcurrentlyandcommunicatewitheachotherthroughmessagepassing.Eachactorhasamailbox,fromwhichitsequentiallyprocessesincomingmessages.Actorsresembledata-owreactivesinthattheyhandlemessageswithoutinversionofcontrolbutdosoonly [5]A.Benveniste,P.LeGuernic,andC.Jacquemot.Synchronousprogrammingwitheventsandrelations:theSIGNALlan-guageanditssemantics.Sci.Comput.Program.,16(2):103–149,1991.[6]G.BerryandG.Gonthier.TheESTERELsynchronouspro-gramminglanguage:design,semantics,implementation.Sci.Comput.Program.,19(2),1992.[7]A.Borning,R.Duisberg,B.Freeman-Benson,A.Kramer,andM.Woolf.Constrainthierarchies.InOOPSLA'87:Confer-enceproceedingsonObject-orientedprogrammingsystems,languagesandapplications,pages48–60,1987.[8]K.Burchett,G.H.Cooper,andS.Krishnamurthi.Lower-ing:astaticoptimizationtechniquefortransparentfunctionalreactivity.InPEPM'07:Proceedingsofthe2007ACMSIG-PLANsymposiumonPartialevaluationandsemantics-basedprogrammanipulation,pages71–80,2007.[9]M.Carlsson.Monadsforincrementalcomputing.InICFP'02:ProceedingsoftheseventhACMSIGPLANinternationalconferenceonFunctionalprogramming,2002.[10]S.Chandrasekaran,O.Cooper,A.Deshpande,M.J.Franklin,J.M.Hellerstein,W.Hong,S.Krishnamurthy,S.R.Madden,F.Reiss,andM.A.Shah.TelegraphCQ:continuousdataowprocessing.InSIGMOD'03:Proceedingsofthe2003ACMSIGMODinternationalconferenceonManagementofdata,pages668–668,2003.[11]J.-L.Colaço,A.Girault,G.Hamon,andM.Pouzet.Towardsahigher-ordersynchronousdata-owlanguage.InEMSOFT'04:Proceedingsofthe4thACMinternationalconferenceonEmbeddedsoftware,pages230–239,NewYork,NY,USA,2004.ACM.[12]G.H.Cooper.IntegratingDataowEvaluationintoaPrac-ticalHigher-OrderCall-by-ValueLanguage.PhDthesis,BrownUniversity,2008.[13]G.H.CooperandS.Krishnamurthi.Embeddingdynamicdataowinacall-by-valuelanguage.InInEuropeanSym-posiumonProgramming,pages294–308,2006.[14]A.Courtney.Frappé:FunctionalreactiveprogramminginJava.InPADL'01:ProceedingsoftheThirdInternationalSymposiumonPracticalAspectsofDeclarativeLanguages,2001.[15]A.Courtney,H.Nilsson,andJ.Peterson.TheYampaar-cade.InHaskell'03:Proceedingsofthe2003ACMSIGPLANworkshoponHaskell,pages7–18,2003.[16]O.DanvyandA.Filinski.Representingcontrol:AstudyoftheCPStransformation.MathematicalStructuresinComputerScience,2(4):361–391,1992.[17]C.J.Date.AguidetotheSQLstandard:auser'sguidetothestandardrelationallanguageSQL.Addison-Wesley,Reading,Mass.[u.a.],1987.ISBN0-201-05777-8.[18]A.J.Demers,J.Gehrke,M.Hong,M.Riedewald,andW.M.White.Towardsexpressivepublish/subscribesystems.InEDBT,pages627–644,2006.[19]C.Elliott.Push-pullfunctionalreactiveprogramming.InHaskellSymposium,2009.[20]C.ElliottandC.Elliott.Functionalimplementationsofcon-tinuousmodeledanimation(expandedversion).InInPro-ceedingsofPLILP/ALP'98,1998.[21]C.ElliottandP.Hudak.Functionalreactiveanimation.InInternationalConferenceonFunctionalProgramming,1997.URLhttp://conal.net/papers/icfp97/.[22]A.Filinski.Representingmonads.InPOPL'94:Proceedingsofthe21stACMSIGPLAN-SIGACTsymposiumonPrinciplesofprogramminglanguages,1994.[23]A.Filinski.Representinglayeredmonads.InPOPL'99:Proceedingsofthe26thACMSIGPLAN-SIGACTsymposiumonPrinciplesofprogramminglanguages,1999.[24]B.N.Freeman-Benson.Kaleidoscope:mixingobjects,con-straints,andimperativeprogramming.InProc.ofOOPSLA/E-COOP,pages77–88,NewYork,NY,USA,1990.ACM.ISBN0-201-52430-X.[25]E.Gamma,R.Helm,R.Johnson,andJ.Vlissides.De-signpatterns:elementsofreusableobject-orientedsoftware.Addison-WesleyLongmanPublishingCo.,Inc.,Boston,MA,USA,1995.ISBN0-201-63361-2.[26]N.Halbwachs,P.Caspi,P.Raymond,andD.Pilaud.ThesynchronousdataowprogramminglanguageLUSTRE.InProceedingsoftheIEEE,pages1305–1320,1991.[27]N.Halbwachs,A.Benveniste,P.Caspi,andP.L.Guernic.Data-owsynchronouslanguages,1993.[28]P.HallerandM.Odersky.ActorsthatUnifyThreadsandEvents.Technicalreport,EcolePolytechniqueFederaledeLausanne,2007.[29]J.Hughes.Generalisingmonadstoarrows.ScienceofCom-puterProgramming,37:67–111,1998.[30]G.E.KrasnerandS.T.Pope.Acookbookforusingthemodel-viewcontrolleruserinterfaceparadigminsmalltalk-80.J.ObjectOrientedProgram.,1(3):26–49,1988.ISSN0896-8438.[31]D.Lea.ConcurrentProgramminginJava:DesignPrinciplesandPatterns(3rdEdition).Addison-WesleyProfessional,2006.ISBN0321256174.[32]J.Liberty.ProgrammingC#.O'Reilly&Associates,Inc.,2003.ISBN0596004893.[33]B.LiskovandL.Shrira.Promises:linguisticsupportforefcientasynchronousprocedurecallsindistributedsystems.SIGPLANNot.,23(7),1988.[34]S.McDirmidandW.C.Hsieh.Superglue:Componentpro-grammingwithobject-orientedsignals.InProc.ofECOOP,pages206–229.Springer,2006.[35]L.A.Meyerovich,A.Guha,J.Baskin,G.H.Cooper,M.Greenberg,A.Bromeld,andS.Krishnamurthi.Flapjax:aprogramminglanguageforajaxapplications.SIGPLANNot.,44(10):1–20,2009.[36]MicrosoftCorporation.ReactiveExtensionsfor.NET(Rx).http://msdn.microsoft.com/en-us/devlabs/ee794896.aspx/,2010.[37]C.Moock.EssentialActionScript3.0.O'Reilly,2007.ISBN0596526946. tail-recursivecontinuationsemantics.However,manyactualusesofcontinuationsinsidewhile-loopsmightratherlooklikethis:varx=0while(x1000000){if(x%100000==0)shift{k=&#x-509;println("+");k();println("-")}x+=1}Duetothelownumberofactualcontinuationsaccessed(only10intotal),throwingastackoverowerrorherewouldnotbeacceptable.Fortunately,wecanputtoworkoncemoretheinitialchoiceoftargetingavariantoftheCPSmonadinsteadofcomposingfunctionsdirectly.WehaveglossedoverthedenitionofmapinclassShift,whichisa(rathersim-ple)staticoptimizationtoavoidbuildingShiftobjectsthatwouldbetrivial,i.e.transformingexpressionxtonewShift(k&#x-509;=k(x)).Regardingtheaboveexample,aconditionalwitha@cpsexpressiononlyinthethenpartwillbetransformedtobuildexactlysuchatrivialShiftobjectintheelsepart.Thus,allbut10Shiftobjectswillbetrivialintheexample.However,thesituationismorecomplexasformapsincewhetheroneiterationistrivialornotdependsonadynamiccondition.Similarinspirittomap,wecanfurtherspecializefortriv-ialShiftinstancesbyrestructuringShiftintoahierarchyofclasses:sealedabstractclassShift[+A,-B,+C]{deffun(f:A=&#x-509;B):C//map,flatMapdeclaredabstract}caseclassShift0[+A,-B](x:A)extendsShift[A,B,B]{defflatMap[A1,B1,C1:B](f:A=⠀Shift[A1,B1,C1])=f(x)defmap[A1](f:A=⠀A1)=Shift0[A1,B,B](f(x))}caseclassShift1[+A,-B,+C](fun0:(A=⠀B)=⠀C)extendsShift[A,B,C]{deffun(f:A=⠀B)=fun0(f)//map,flatMapimplementedasbefore}WiththismodiedCPSmonadimplementationwecanimplementamoreefcienttranslationofwhile-loops:defloop()=if(condition唀){body䈀match{caseShift0(x)=䈀loop()casectx:Shift1=䈀ctx.flatMap{_=䈀loop()}}}else{Shift0[Unit,Unit]()}loop()Inessence,wehaveinlinedthedynamicdispatchandthedenitionofShift0.flatMap.Forthetrivialcase,thismakestherecursivecalladirecttail-callagainandthestan-dard,intraproceduraltail-recursionoptimizationperformedbytheScalacompilerwilltranslatethiscalltoabranchinstruction.