Slide 1

Slide 1 text

RxJava:  Reactive   Extensions  in  Scala   Ma#  Jacobs  /  @ma#rjacobs   h#ps://github.com/ma#rjacobs/RxScalaDemo   h#p://techblog.ne>lix.com    

Slide 2

Slide 2 text

Agenda   •  For  library  writers   How  does  RxJava  support  Scala  in  parEcular?   How  does  RxJava  support  many  JVM  languages?   •  For  RxJava  consumers  (or  prospecEve  consumers)  

Slide 3

Slide 3 text

Agenda   •  For  library  writers   •  How  does  RxJava  support  Scala  in  parEcular?   How  does  RxJava  support  many  JVM  languages?   •  For  RxJava  consumers  (or  prospecEve  consumers)  

Slide 4

Slide 4 text

Agenda   •  For  library  writers   •  How  does  RxJava  support  Scala  in  parEcular?   •  How  does  RxJava  support  many  JVM  languages?   •  For  RxJava  consumers  (or  prospecEve  consumers)  

Slide 5

Slide 5 text

Agenda   •  For  library  writers   •  How  does  RxJava  support  Scala  in  parEcular?   •  How  does  RxJava  support  many  JVM  languages?   •  For  RxJava  consumers  (or  prospecEve  consumers)   •  How  do  other  concurrency/collecEon  constructs  map  onto   Observable?  

Slide 6

Slide 6 text

Agenda   •  For  library  writers   •  How  does  RxJava  support  Scala  in  parEcular?   •  How  does  RxJava  support  many  JVM  languages?   •  For  RxJava  consumers  (or  prospecEve  consumers)   •  How  do  other  concurrency/collecEon  constructs  map  onto   Observable?   •  What  can  I  do  with  it?  

Slide 7

Slide 7 text

RxJava  Design  Goals   •  Adherence  to  .NET  spec   Type  safety   Support  all  JVM  languages  in  a  language-­‐naEve  way   Consumers  can  pick  which  languages  they  want  to  depend  on   Consumers  can  mix  mulEple  JVM  languages  in  the  same     project  

Slide 8

Slide 8 text

RxJava  Design  Goals   •  Adherence  to  .NET  spec   •  Type  safety   Support  all  JVM  languages  in  a  language-­‐naEve  way   Consumers  can  pick  which  languages  they  want  to  depend  on   Consumers  can  mix  mulEple  JVM  languages  in  the  same     project  

Slide 9

Slide 9 text

RxJava  Design  Goals   •  Adherence  to  .NET  spec   •  Type  safety   •  Support  all  JVM  languages  in  a  language-­‐naEve  way   Consumers  can  pick  which  languages  they  want  to  depend  on   Consumers  can  mix  mulEple  JVM  languages  in  the  same     project  

Slide 10

Slide 10 text

RxJava  Design  Goals   •  Adherence  to  .NET  spec   •  Type  safety   •  Support  all  JVM  languages  in  a  language-­‐naEve  way   •  Consumers  can  pick  which  languages  they  want  to  depend  on   Consumers  can  mix  mulEple  JVM  languages  in  the  same     project  

Slide 11

Slide 11 text

RxJava  Design  Goals   •  Adherence  to  .NET  spec   •  Type  safety   •  Support  all  JVM  languages  in  a  language-­‐naEve  way   •  Consumers  can  pick  which  languages  they  want  to  depend  on   •  Consumers  can  mix  mulEple  languages  in  the  same  project  

Slide 12

Slide 12 text

Java  Observable   public  class  Observable  {    public    Observable  map  (            Func1  f);   }     public  interface  Func1  {          public  R  call(T1  t1);   }     Observable  o  =  Observable.just(1);     o.map(new  Func1()  {    @Override    public  String  call(Integer  i)  {                  return  (i  +  3).toString();            }   });  

Slide 13

Slide 13 text

Java  Observable   public  class  Observable  {    public    Observable  map  (            Func1  f);   }     public  interface  Func1  {          public  R  call(T1  t1);   }     Observable  o  =  Observable.just(1);     o.map(new  Func1()  {    @Override    public  String  call(Integer  i)  {                  return  (i  +  3).toString();            }   });  

Slide 14

Slide 14 text

Java  Observable   Observable  o  =  Observable.just(1);     o.map(new  Func1()  {    @Override    public  String  call(Integer  i)  {                  return  (i  +  3).toString();            }   });  

Slide 15

Slide 15 text

Using  Observable  in  Java   Observable  o  =  Observable.just(1);     o.map(new  Func1()  {    @Override    public  String  call(Integer  i)  {                  return  (i  +  3).toString();           Observable  o  =  Observable.just(1);     o.map(new  Func1()  {    @Override    public  String  call(Integer  i)  {                  return  (i  +  3).toString();            }   });;  

Slide 16

Slide 16 text

Using  Observable  in  Java   Observable  o  =  Observable.just(1);     o.map(new  Func1()  {    @Override    public  String  call(Integer  i)  {                  return  (i  +  3).toString();           Observable  o  =  Observable.just(1);     o.map(new  Func1()  {    @Override    public  String  call(Integer  i)  {                  return  (i  +  3).toString();            }   });;  

Slide 17

Slide 17 text

Using  Observable  in  Scala   Observable  o  =  Observable.just(1);     o.map(new  Func1()  {    @Override    public  String  call(Integer  i)  {                  return  (i  +  3).toString();       val  o:  Observable[Int]  =  Observable.just(1)       o.map(i  =>  (i  +  3).toString)    

Slide 18

Slide 18 text

Using  Observable  in  Scala   Observable  o  =  Observable.just(1);     o.map(new  Func1()  {    @Override    public  String  call(Integer  i)  {                  return  (i  +  3).toString();       val  o:  Observable[Int]  =  Observable.just(1)       o.map(i  =>  (i  +  3).toString)    

Slide 19

Slide 19 text

Using  Observable  in  Groovy   Observable  o  =  Observable.just(1);     o.map(new  Func1()  {    @Override    public  String  call(Integer  i)  {                  return  (i  +  3).toString();       Observable  o  =  Observable.just(1)       o.map  {  i  -­‐>  (i  +  3).toString  }  

Slide 20

Slide 20 text

Using  Observable  in  Groovy   Observable  o  =  Observable.just(1);     o.map(new  Func1()  {    @Override    public  String  call(Integer  i)  {                  return  (i  +  3).toString();       Observable  o  =  Observable.just(1)       o.map  {  i  -­‐>  (i  +  3).toString  }  

Slide 21

Slide 21 text

Multiple  Language  Support   •  Java          public    Observable  map(Func1  f);   Scala            def  map[R](f:  T  =>  R)   Groovy          def  map(groovy.lang.Closure)  

Slide 22

Slide 22 text

Multiple  Language  Support   •  Java          public    Observable  map(Func1  f);   •  Scala            def  map[R](f:  T  =>  R):  Observable[R]   Groovy          def  map(groovy.lang.Closure)  

Slide 23

Slide 23 text

Multiple  Language  Support   •  Java          public    Observable  map(Func1  f);   •  Scala            def  map[R](f:  T  =>  R):  Observable[R]   •  Groovy          def  Observable  map(groovy.lang.Closure  f)  

Slide 24

Slide 24 text

Multiple  Language  Support   rx/Observable.class   map(Func1  f);     map(f:  T  =>  R)   map(Closure  f)  

Slide 25

Slide 25 text

Scala  support   •  In  order  to  support  Scala  naEvely,  we  need:   •  Good  interop  between  Scala  funcEons  and  RxJava  core    

Slide 26

Slide 26 text

Scala  support   •  In  order  to  support  Scala  naEvely,  we  need:   •  Good  interop  between  Scala  funcEons  and  RxJava  core   •  Ability  to  add  idiomaEc  Scala  methods  to  rx.Observable   •  apply()  factory  methods   •  ++   •  drop(n:  Int)  instead  of  skip(n:  Int)     •  zip  always  returns  a  tuple  

Slide 27

Slide 27 text

Implicit  conversions   •  We  have:            public    Observable  map(Func1  f);   •   We  want:                      def  map[R](f:  T  =>  R):  Observable[R]     Implicit  conversion:          implicit  def  toRxFunc1[A,  B](f:  (A  =>  B)):  Func1[A,  B]  =          new  Func1[A,  B]  {              def  call(a:  A):  B  =  f(a)          }     We  added  18  such  conversions  from  Scala  funcEons  to  Rx  funcEons   Lots  of  duplicaEve  code  –  could  macros  help?      

Slide 28

Slide 28 text

Implicit  conversions   •  We  have:            public    Observable  map(Func1  f);   •   We  want:                      def  map[R](f:  T  =>  R):  Observable[R]     •  Implicit  conversion:          implicit  def  toRxFunc1[A,  B](f:  (A  =>  B)):  Func1[A,  B]  =              new  Func1[A,  B]  {                  def  call(a:  A):  B  =  f(a)              }     We  added  18  such  conversions  from  Scala  funcEons  to  Rx  funcEons   Lots  of  duplicaEve  code  –  could  macros  help?      

Slide 29

Slide 29 text

Implicit  conversions   •  We  have:            public    Observable  map(Func1  f);   •   We  want:                      def  map[R](f:  T  =>  R):  Observable[R]     •  Implicit  conversion:          implicit  def  toRxFunc1[A,  B](f:  (A  =>  B)):  Func1[A,  B]  =              new  Func1[A,  B]  {                  def  call(a:  A):  B  =  f(a)              }   •  We  added  18  such  conversions  from  Scala  funcEons  to  Rx  funcEons   •  Lots  of  duplicaEve  code  for  ariEes–  could  macros  help?      

Slide 30

Slide 30 text

Scala  support   •  In  order  to  support  Scala  naEvely,  we  need:   •  Good  interop  between  Scala  funcEons  and  RxJava  core   •  Ability  to  add  idiomaEc  Scala  methods  to  rx.Observable   •  apply()  factory  methods   •  ++   •  drop(n)  instead  of  skip(n)     •  zip  always  returns  a  tuple  

Slide 31

Slide 31 text

Extension  methods   •  Implicit  conversion  to  rx.lang.scala.Observable        

Slide 32

Slide 32 text

Extension  methods   •  Implicit  conversion  to  rx.lang.scala.Observable         implicit  def  toScalaObs[T](asJava:  rx.Observable[T])  =        new  rx.lang.scala.Observable(asJava)  

Slide 33

Slide 33 text

Extension  methods   •  Implicit  conversion  to  rx.lang.scala.Observable         implicit  def  toScalaObs[T](asJava:  rx.Observable[T])  =        new  rx.lang.scala.Observable(asJava)     •  Define  new  methods  on  rx.lang.scala.Observable      class  Observable[+T](asJava:  rx.Observable[T])  {          def  ++[U  >:  T](that:  Observable[U]):  Observable[U]  =  ...          def  drop(int:  N):  Observable[T]  =  ...          ...      }  

Slide 34

Slide 34 text

Extension  methods   •  Implicit  conversion  to  rx.lang.scala.Observable   •  Define  all  new  methods  on  rx.lang.scala.Observable     •  Works,  but…   •  Other  languages  can’t  consume  rx.lang.scala.Observable  

Slide 35

Slide 35 text

Extension  methods   •  Implicit  conversion  to  rx.lang.scala.Observable   •  Define  all  new  methods  on  rx.lang.scala.Observable     •  Works,  but…   •  Other  languages  can’t  consume  rx.lang.scala.Observable   •  We  incur  the  cost  of  wrapping  very  frequently  

Slide 36

Slide 36 text

Scala  value  classes  (SIP-­‐15)   •  Thanks  to  @samuelgrue#er,  @jmhofer        package  rx.lang.scala        class  Observable[+T]  (val  asJava:  rx.Observable[_  <:  T])        extends  AnyVal  

Slide 37

Slide 37 text

Scala  value  classes  (SIP-­‐15)   •  Thanks  to  @samuelgrue#er        package  rx.lang.scala        class  Observable[+T]  (val  asJava:  rx.Observable[_  <:  T])        extends  AnyVal       •  Does  not  incur  wrapping  costs  

Slide 38

Slide 38 text

Scala  value  classes  (SIP-­‐15)   •  Thanks  to  @samuelgrue#er        package  rx.lang.scala        class  Observable[+T]  (val  asJava:  rx.Observable[_  <:  T])        extends  AnyVal       •  Does  not  incur  wrapping  costs   •  Works  transparently  with  any  other  JVM  language  

Slide 39

Slide 39 text

Scala  value  class  example   object  Producer  {      def  stream():  rx.lang.scala.Observable[String]  =  {          val  stringList  =  (1  to  100).map(_  =>  "a")          Observable(stringList:  _*)      }   }     public  class  SampleConsumer  {          public  static  void  main(String[]  args)  {            Observable  s  =  Producer.stream();                    s.subscribe(new  Action1()  {                          @Override                          public  void  call(String  o)  {                                  System.out.println("onNext  :  "  +  o);                          }});}}  

Slide 40

Slide 40 text

Scala  value  class  example   object  Producer  {      def  stream():  rx.lang.scala.Observable[String]  =  {          val  stringList  =  (1  to  100).map(_  =>  "a")          Observable(stringList:  _*)      }   }     public  class  SampleConsumer  {          public  static  void  main(String[]  args)  {                rx.Observable  s  =  Producer.stream();                  s.subscribe(new  Action1()  {                        @Override                        public  void  call(String  o)  {                                System.out.println("onNext  :  "  +  o);                        }});                  }            }  

Slide 41

Slide 41 text

Multiple  Language  Support   rx/Observable.class   map(Func1  f);     map(f:  T  =>  R)   map(Closure  f)  

Slide 42

Slide 42 text

Implementation  Strategies   •  All  JVM  languages  supported  by  rx.Observable  via  source      public  class  Observable  {          public    Observable  map(Func1  f);          public    Observable  map(groovy.lang.Closure  f);          public    Observable  map(clojure.lang.IFn  f);            }    

Slide 43

Slide 43 text

Implementation  Strategies   •  All  JVM  languages  supported  by  rx.Observable  via  source      public  class  Observable  {          public    Observable  map(Func1  f);          public    Observable  map(groovy.lang.Closure  f);          public    Observable  map(clojure.lang.IFn  f);            }     •  Would  force  consumers  of  RxJava  to  pull  in  libraries  for:   •  Clojure,  Groovy,  JRuby,  Kotlin,  …  

Slide 44

Slide 44 text

Implementation  Strategies   •  All  JVM  languages  supported  by  rx.Observable  via  source      public  class  Observable  {          public    Observable  map(Func1  f);          public    Observable  map(groovy.lang.Closure  f);          public    Observable  map(clojure.lang.IFn  f););            }     •  Would  force  consumers  of  RxJava  to  pull  in  libraries  for:   •  Clojure,  Groovy,  JRuby,  Kotlin,  …  

Slide 45

Slide 45 text

Implementation  Strategies   •  Method  overloads  with  Object  arguments        public  class  Observable  {          public    Observable  map(Func1  f);          public    Observable  map(Object  f);      }    

Slide 46

Slide 46 text

Implementation  Strategies   •  Method  overloads  with  Object  arguments        public  class  Observable  {          public    Observable  map(Func1  f);          public    Observable  map(Object  f)  {              Func1  typedFunc  =  LanguageAdaptor.getFunc(f);              this.map(typedFunc);          }      }    

Slide 47

Slide 47 text

Implementation  Strategies   •  Method  overloads  with  Object  arguments        public  class  Observable  {          public    Observable  map(Func1  f);          public    Observable  map(Object  f)  {              Func1  typedFunc  =  LanguageAdaptor.getFunc(f);              this.map(typedFunc);          }      }    

Slide 48

Slide 48 text

Implementation  Strategies   •  Method  overloads  with  Object  arguments        public  class  Observable  {          public    Observable  map(Func1  f);          public    Observable  map(Object  f)  {              Func1  typedFunc  =  LanguageAdaptor.getFunc(f);              this.map(typedFunc);          }      }        public  class  GroovyAdaptor  {          public    Func1  getFunc(Object  o)  {              if  (o.getClass().equals(groovy.lang.Closure.class)                  //convert  Closure  to  Func1  and  return          }  }    

Slide 49

Slide 49 text

Implementation  Strategies   •  Method  overloads  with  Object  arguments        public  class  Observable  {          public    Observable  map(Func1  f);          public    Observable  map(Object  f);      }   •  This  works!  –  RxJava  up  to  0.11  used  this  approach    

Slide 50

Slide 50 text

Implementation  Strategies   •  Method  overloads  with  Object  arguments        public  class  Observable  {          public    Observable  map(Func1  f);          public    Observable  map(Object  f);      }   •  This  works!  –  RxJava  up  to  0.11  used  this  approach   •  However,  not  typesafe     val  o:  Observable[Int]  =  Observable.just(1)     o.map((l:  List[String])  =>  l.head)      

Slide 51

Slide 51 text

Implementation  Strategies   •  Method  overloads  with  Object  arguments        public  class  Observable  {          public    Observable  map(Func1  f);          public    Observable  map(Object  f);      }   •  This  works!  –  RxJava  up  to  0.11  used  this  approach   •  However,  not  typesafe     val  o:  Observable[Int]  =  Observable.just(1)     o.map((l:  List[String])  =>  l.head)      

Slide 52

Slide 52 text

Implementation  Strategies   •  Method  overloads  with  Object  arguments        public  class  Observable  {          public    Observable  map(Func1  f);          public    Observable  map(Object  f);      }   •  This  works!  –  RxJava  up  to  0.11  used  this  approach   •  However,  not  typesafe     val  o:  Observable[Int]  =  Observable.just(1)     o.map((l:  List[String])  =>  l.head)     [success]  Total  time:  0s    

Slide 53

Slide 53 text

Implementation  Strategies   •  Method  overloads  with  Object  arguments        public  class  Observable  {          public    Observable  map(Func1  f);          public    Observable  map(Object  f);      }   •  This  works!  –  RxJava  up  to  0.11  used  this  approach   •  However,  not  typesafe     val  o:  Observable[Int]  =  Observable.just(1)     o.map((l:  List[String])  =>  l.head)     [success]  Total  time:  0s    

Slide 54

Slide 54 text

Implementation  Strategies   •  StaEc  bytecode  rewriEng  

Slide 55

Slide 55 text

Implementation  Strategies   •  StaEc  bytecode  rewriEng            public  class  Observable  {          public    Observable  map(Func1  f);          public    Observable  map(Object  f);      }  

Slide 56

Slide 56 text

Implementation  Strategies   •  StaEc  bytecode  rewriEng            public  class  Observable  {          public    Observable  map(Func1  f);          public    Observable  map(Object  f);      }  

Slide 57

Slide 57 text

Implementation  Strategies   •  StaEc  bytecode  rewriEng            public  class  Observable  {          public    Observable  map(Func1  f);      }           rx/Observable.class   Observable   map(Func1  f)   rx/Observable.class   Observable   map(Closure  f)   rx/Observable.class   Observable   map(Func1  f)   Observable   map(Closure  f)   Package  (1)  

Slide 58

Slide 58 text

Implementation  Strategies   •  StaEc  bytecode  rewriEng            public  class  Observable  {          public    Observable  map(Func1  f);      }           rx/Observable.class   Observable   map(Func1  f)   rx/Observable.class   Observable   map(Closure  f)   rx/Observable.class   Observable   map(Func1  f)   Observable   map(Closure  f)   Package  (1)   Code-­‐gen  

Slide 59

Slide 59 text

Implementation  Strategies   •  StaEc  bytecode  rewriEng            public  class  Observable  {          public    Observable  map(Func1  f);      }           rx/Observable.class   Observable   map(Func1  f)   rx/Observable.class   Observable   map(Closure  f)   rx/Observable.class   Observable   map(Func1  f)   Observable   map(Closure  f)   Package  (1)   Code-­‐gen   Package  (2)  

Slide 60

Slide 60 text

Implementation  Strategies   •  StaEc  bytecode  rewriEng            public  class  Observable  {          public    Observable  map(Func1  f);      }           rx/Observable.class     Observable  map(Func1  f)   Observable  map(Closure  f)    

Slide 61

Slide 61 text

Implementation  Strategies   •  StaEc  bytecode  rewriEng            public  class  Observable  {          public    Observable  map(Func1  f);      }           •  Causes  havoc  on  tools  unless  we  depend  on  all  languages   (scalac,  IDEs,  …)   rx/Observable.class     Observable  map(Func1  f)   Observable  map(Closure  f)    

Slide 62

Slide 62 text

Implementation  Strategies   •  StaEc  bytecode  rewriEng            public  class  Observable  {          public    Observable  map(Func1  f);      }           •  Causes  havoc  on  tools  unless  we  depend  on  all  languages   (scalac,  IDEs,  …)   Observable.class     Observable  map(Func1  f)   Observable  map(Closure  f)    

Slide 63

Slide 63 text

Implementation  Strategies   •  Dynamic  bytecode  rewriEng    

Slide 64

Slide 64 text

Implementation  Strategies   •  Dynamic  bytecode  rewriEng   •  If  there  is  1  factory  method  for  gekng  rx.Observables:   •  Can  rewrite  that  to  provide  an  rx.DynamicObservable  (which  only   exists  at  runEme  and  extends  rx.Observable)   •  rx.DynamicObservable  has  the  Object-­‐overloaded  method      public    DynamicObservable  map(Object  f);      with  an  implementaEon  which  properly  delegates  to            language-­‐specific  adaptors      

Slide 65

Slide 65 text

Implementation  Strategies   •  Dynamic  bytecode  rewriEng   •  If  there  is  1  factory  method  for  gekng  rx.Observables:   •  Can  rewrite  that  to  provide  an  rx.DynamicObservable  (which  only   exists  at  runEme  and  extends  rx.Observable)   •  rx.DynamicObservable  has  the  Object-­‐overloaded  method      public    DynamicObservable  map(Object  f);      with  an  implementaEon  which  properly  delegates  to            language-­‐specific  adaptors   •  Needless  to  say,  this  is  really  complex  and  hard  to  debug   •  Also,  we  don’t  have  only  1  entry  point   •  Also,  really  only  works  for  Groovy    

Slide 66

Slide 66 text

Implementation  Strategies   •  Dynamic  bytecode  rewriEng   •  If  there  is  1  factory  method  for  gekng  rx.Observables:   •  Can  rewrite  that  to  provide  an  rx.DynamicObservable  (which  only   exists  at  runEme  and  extends  rx.Observable)   •  rx.DynamicObservable  has  the  Object-­‐overloaded  method      public    DynamicObservable  map(Object  f);      with  an  implementaEon  which  properly  delegates  to            language-­‐specific  adaptors   •  Needless  to  say,  this  is  really  complex  and  hard  to  debug   •  Also,  we  don’t  have  only  1  entry  point   •  Also,  really  only  works  for  Groovy    

Slide 67

Slide 67 text

Implementation  Strategies   •  Give  up  

Slide 68

Slide 68 text

Implementation  Strategies   •  Give  up  on  solving  this  in  the  general  case  

Slide 69

Slide 69 text

Implementation  Strategies   •  Give  up  on  solving  this  in  the  general  case  

Slide 70

Slide 70 text

Implementation  Strategies   •  Give  up  on  solving  this  in  the  general  case   •  Instead,  solve  each  language  separately   •  Scala  –  implicit  conversions  and  value  class  

Slide 71

Slide 71 text

Implementation  Strategies   •  Give  up  on  solving  this  in  the  general  case   •  Instead,  solve  each  language  separately   •  Scala  –  implicit  conversions  and  value  class   •  Groovy  –  extension  modules  

Slide 72

Slide 72 text

Implementation  Strategies   •  Give  up  on  solving  this  in  the  general  case   •  Instead,  solve  each  language  separately   •  Scala  –  implicit  conversions  and  value  class   •  Groovy  –  extension  modules   •  Clojure  –  something  with  macros  (????)    

Slide 73

Slide 73 text

Implementation  Strategies   •  Give  up  on  solving  this  in  the  general  case   •  Instead,  solve  each  language  separately   •  Scala  –  implicit  conversions  and  value  class   •  Groovy  –  extension  modules   •  Clojure  –  something  with  macros  (????)   •  JRuby  –  Extension  methods  (I  think)  

Slide 74

Slide 74 text

Implementation  Strategies   •  Give  up  on  solving  this  in  the  general  case   •  Instead,  solve  each  language  separately   •  Scala  –  implicit  conversions  and  value  class   •  Groovy  –  extension  modules   •  Clojure  –  something  with  macros  (????)   •  JRuby  –  Extension  methods  (I  think)   •  Kotlin  –  just  received  this  -­‐  apparently  none  since  Kotlin  supports   Java  8  SAMs    

Slide 75

Slide 75 text

Implementation  Strategies   •  Give  up  on  solving  this  in  the  general  case   •  Instead,  solve  each  language  separately   •  Scala  –  implicit  conversions  and  value  class   •  Groovy  –  extension  modules   •  Clojure  –  something  with  macros  (????)   •  JRuby  –  Extension  methods  (I  think)   •  Kotlin  –  just  received  this  -­‐  apparently  none  since  Kotlin  supports   Java  8  SAMs   •  Lessons  learned   •  Leverage  each  language’s  specific  features  

Slide 76

Slide 76 text

Implementation  Strategies   •  Give  up  on  solving  this  in  the  general  case   •  Instead,  solve  each  language  separately   •  Scala  –  implicit  conversions  and  value  class   •  Groovy  –  extension  modules   •  Clojure  –  something  with  macros  (????)   •  JRuby  –  Extension  methods  (I  think)   •  Kotlin  –  just  received  this  -­‐  apparently  none  since  Kotlin  supports   Java  8  SAMs   •  Lessons  learned   •  Leverage  each  language’s  specific  features   •  Bytecode  generaEon  is  probably  not  the  correct  soluEon    

Slide 77

Slide 77 text

Implementation  Strategies   •  Give  up  on  solving  this  in  the  general  case   •  Instead,  solve  each  language  separately   •  Scala  –  implicit  conversions  and  value  class   •  Groovy  –  extension  modules   •  Clojure  –  something  with  macros  (????)   •  JRuby  –  Extension  methods  (I  think)   •  Kotlin  –  just  received  this  -­‐  apparently  none  since  Kotlin  supports   Java  8  SAMs   •  Lessons  learned   •  Leverage  each  language’s  specific  features   •  Bytecode  generaEon  is  probably  not  the  correct  soluEon   •  An  implementaEon  from  the  language  community  is  vastly   preferable  than  a  leaky  global  soluEon      

Slide 78

Slide 78 text

Agenda   •  For  library  writers   •  How  does  RxJava  support  Scala  in  parEcular?   •  How  does  RxJava  support  many  JVM  languages?   •  For  RxJava  consumers  (or  prospecEve  consumers)   •  How  do  other  concurrency  constructs  map  onto  Observable?   •  What  can  I  do  with  it?  

Slide 79

Slide 79 text

Mapping  onto  Observable[T]   •  scala.collecEon.Iterable[T]   •  scala.concurrent.Future[T]   •  com.twi#er.uEl.Future[T]   •  akka.actor.Actor  

Slide 80

Slide 80 text

Mapping  onto  Observable[T]   •  scala.collecEon.Iterable[T]   •  scala.concurrent.Future[T]   •  com.twi#er.uEl.Future[T]   •  akka.actor.Actor   •  rx.lang.scala.Observable  has  a  factory  method:          def  apply[T](func:  Observer[T]  =>  Subscription)  

Slide 81

Slide 81 text

Iterable[T]   •  scala.collecEon.Iterable[T]   •  Need  to  implement:      def  apply[T](func:  Observer[T]  =>  Subscription)  

Slide 82

Slide 82 text

Iterable[T]     def  toObservable[T](iterableT:  Iterable[T]):  Observable[T]  =          Observable((observer:  Observer[T])  =>  {              try  {                  iterableT.foreach(t  =>  observer.onNext(t))                  observer.onCompleted()              }  catch  {                  case  ex:  Throwable  =>  observer.onError(ex)              }                //no  unsubscribe              new  Subscription  {                  override  def  unsubscribe()  =  {}              }          })  

Slide 83

Slide 83 text

Mapping  onto  Observable[T]   •  scala.uEl.concurrent.Future[T]   •  Need  to  implement:      def  apply[T](func:  Observer[T]  =>  Subscription)  

Slide 84

Slide 84 text

scala.concurrent.Future[T]   def  toObservable[T](futureT:  scala.concurrent.Future[T])  =        Observable((observer:  Observer[T])  =>  {          import  ExecutionContext.Implicits.global            futureT.onComplete  {              case  Success(t)  =>  {                  observer.onNext(t)                  observer.onCompleted()                }              case  Failure(ex)  =>  observer.onError(ex)            }        //no  present  way  to  cancel  a  Scala  future      new  Subscription  {  override  def  unsubscribe()  =  {}  }   })  

Slide 85

Slide 85 text

com.twitter.util.Future[T]   def  toObservable[T](futureT:  com.twitter.util.Future[T])  =        Observable((observer:  Observer[T])  =>  {          futureT.onSuccess  {  t  =>  {              observer.onNext(t)              observer.onCompleted()          }          }.onFailure  {              ex  =>  observer.onError(ex)          }          new  Subscription  {      override  def  unsubscribe()  =  {        futureT.raise(new  FutureCancelledException)              }          }      })  

Slide 86

Slide 86 text

Mapping  onto  Observable[T]   •  akka.actor.Actor  

Slide 87

Slide 87 text

Mapping  onto  Observable   •  akka.actor.Actor   •  We’re  not  sure  yet!   •  One  interesEng  direcEon  would  be  to  set  up  an  ActorScheduler   that  does  work  on  actors  instead  of  threads   •  More  to  come  on  this  –  if  you’re  interested,  we’d  love  some   input!  

Slide 88

Slide 88 text

Demo:  HTTP  Client   •  Product  Goal:  Retrieve  all  menEons  of  me  (@ma#rjacobs)  

Slide 89

Slide 89 text

Demo:  HTTP  Client   •  Product  Goal:  Retrieve  all  menEons  of  me  (@ma#rjacobs)   •  ImplementaEon:  Business  logic  on  top  of  rxjava-­‐apache-­‐h#p   •  Part  of  rxjava-­‐contrib  

Slide 90

Slide 90 text

Demo:  HTTP  Client   •  Product  Goal:  Retrieve  all  menEons  of  me  (@ma#rjacobs)   •  ImplementaEon:  Business  logic  on  top  of  rxjava-­‐apache-­‐h#p   •  REST:   •  h#ps://api.twi#er.com/1.1/statuses/menEons_Emeline.json   •  returns  JSON  blob  with  all  menEons    

Slide 91

Slide 91 text

Demo:  HTTP  Client   •  Product  Goal:  Retrieve  all  menEons  of  me  (@ma#rjacobs)   •  ImplementaEon:  Business  logic  on  top  of  rxjava-­‐apache-­‐h#p   •  REST:   •  h#ps://api.twi#er.com/1.1/statuses/menEons_Emeline.json   •  returns  JSON  blob  with  all  menEons   •  Seq[Mention]  /  Future[Seq[Mention]]  /  Observable[Mention]      

Slide 92

Slide 92 text

Demo:  HTTP  Client   •  Product  Goal:  Retrieve  all  menEons  of  me  (@ma#rjacobs)   •  ImplementaEon:  Business  logic  on  top  of  rxjava-­‐apache-­‐h#p   •  REST:   •  h#ps://api.twi#er.com/1.1/statuses/menEons_Emeline.json   •  returns  JSON  blob  with  all  menEons   •  Seq[Mention]  /  Future[Seq[Mention]]  /  Observable[Mention]   •  Streaming   •  h#ps://userstream.twi#er.com/1.1/user.json   •  returns  infinite  stream  of  JSON  using  Transfer-­‐Encoding:  chunked    

Slide 93

Slide 93 text

Demo:  HTTP  Client   •  Product  Goal:  Retrieve  all  menEons  of  me  (@ma#rjacobs)   •  ImplementaEon:  Business  logic  on  top  of  rxjava-­‐apache-­‐h#p   •  REST:   •  h#ps://api.twi#er.com/1.1/statuses/menEons_Emeline.json   •  returns  JSON  blob  with  all  menEons   •  Seq[Mention]  /  Future[Seq[Mention]]  /  Observable[Mention]   •  Streaming   •  h#ps://userstream.twi#er.com/1.1/user.json   •  returns  infinite  stream  of  JSON  using  Transfer-­‐Encoding:  chunked   •  Stream[Mention]  /  Observable[Mention]   •  In  both  cases,  Observable[Mention]  is  appropriate      

Slide 94

Slide 94 text

Twitter  business  logic   •  case  class  Mention(time,  name,  screenName,  imageUrl)  

Slide 95

Slide 95 text

Twitter  business  logic   •  case  class  Mention(time,  name,  screenName,  imageUrl)   •  def  getResponse(uri:  String):    Observable[ObservableHttpResponse]   •  ObservableHttp.createRequest(apacheReq,  client)  

Slide 96

Slide 96 text

Twitter  business  logic   •  case  class  Mention(time,  name,  screenName,  imageUrl)   •  def  getResponse(uri:  String):    Observable[ObservableHttpResponse]   •  def  getJson(resp:  ObservableHttpResponse):    Observable[Map[String,  Any]]   •  val  bytesObs    =  httpResp.getContent   •  val  stringObs  =  bytesObs.map(new  String(_))   •  val  jsonObs      =  stringObs.map(  //JSON  parsing)  

Slide 97

Slide 97 text

Twitter  business  logic   •  case  class  Mention(time,  name,  screenName,  imageUrl)   •  def  getResponse(uri:  String)  :          Observable[ObservableHttpResponse]   •  def  getJson(resp:  ObservableHttpResponse):    Observable[Map[String,  Any]]   •  def  getMention(m:  Map[String,  Any]):  Mention   •  val  userMap:  Map[String,  Any]  =  m("user”)   •  val  name  =  userMap("name”)   •  val  screenName  =  userMap("screen_name”)     •  val  imageUrl  =  userMap("profile_image_url”)   •  val  time  =  parseDate(m("created_at”)   •  Mention(time,  name,  screenName,  imageUrl)  

Slide 98

Slide 98 text

Twitter  REST  Client   •  case  class  Mention(time,  name,  screenName,  imageUrl)   •  def  getResponse(uri:  String)  :          Observable[ObservableHttpResponse]   •  def  getJson(resp:  ObservableHttpResponse):    Observable[Map[String,  Any]]   •  def  getMention(m:  Map[String,  Any]):  Mention                val  mentionObs:  Observable[Mention]  =  for  {          httpResp  <-­‐  getResponse(REST_URI)          jsonMap  <-­‐  getJson(httpResp)      }  yield  getMention(jsonMap)  

Slide 99

Slide 99 text

Twitter  REST  Client   •  case  class  Mention(time,  name,  screenName,  imageUrl)        val  mentionObs:  Observable[Mention]  =  for  {          httpResp  <-­‐  getResponse(REST_URI)          jsonMap  <-­‐  getJson(httpResp)      }  yield  getMention(jsonMap)     Result:     onNext  :  Mention(2013-­‐09-­‐24T00:26:22.000-­‐07:00,Alexy   Khrabrov,khrabrov,http://a0.twimg.com/profile_images/61382665/ Alexy_20080710_0999_normal.jpg)     onNext  :  Mention(2013-­‐09-­‐23T19:56:46.000-­‐07:00,Ben   Christensen,benjchristensen,http://a0.twimg.com/profile_images/ 3761650768/e602460a06e8a038b945e44e9df7585b_normal.jpeg)     onCompleted()  

Slide 100

Slide 100 text

Twitter  Streaming  client   •  case  class  Mention(time,  name,  screenName,  imageUrl)   •  def  getResponse(uri:  String)  :          Observable[ObservableHttpResponse]   •  def  getJson(resp:  ObservableHttpResponse):    Observable[Map[String,  Any]]   •  def  getMention(m:  Map[String,  Any]):  Mention              val  mentionObs:  Observable[Mention]  =  for  {          httpResp  <-­‐  getResponse(STREAMING_URI)          jsonMap  <-­‐  getJson(httpResp)  if   jsonMentionsMe(jsonMap,  "mattrjacobs")      }  yield  getMention(jsonMap)  

Slide 101

Slide 101 text

DEMO   •  Tweet  at  @ma#rjacobs  

Slide 102

Slide 102 text

Upcoming  Coursera  course   •  Principles  of  ReacEve  Programming   •  Taught  by:   •  MarEn  Odersky   •  Erik  Meijer   •  Roland  Kuhn   •  Starts  Nov  4   •  h#p://www.coursera.org/course/reacEve  

Slide 103

Slide 103 text

Questions