Upgrade to Pro — share decks privately, control downloads, hide ads and more …

RxJava: Reactive Extensions in Scala

Avatar for Matt Jacobs Matt Jacobs
October 18, 2013

RxJava: Reactive Extensions in Scala

RxJava is a library for composing asynchronous and event-based programs by using observable sequences for the Java VM. In this presentation, I discuss some interesting consequences of building a library intended to be consumed by multiple JVM languages. I also work through some examples of using this abstraction in Scala.

Presented at SF-Scala on October 17, 2013. http://www.meetup.com/SF-Scala/events/142643212.

RxJava at Netflix: http://techblog.netflix.com/2013/02/rxjava-netflix-api.html

RxJava on Github: https://github.com/Netflix/RxJava

Avatar for Matt Jacobs

Matt Jacobs

October 18, 2013
Tweet

More Decks by Matt Jacobs

Other Decks in Programming

Transcript

  1. RxJava:  Reactive   Extensions  in  Scala   Ma#  Jacobs  /

     @ma#rjacobs   h#ps://github.com/ma#rjacobs/RxScalaDemo   h#p://techblog.ne>lix.com    
  2. Agenda   •  For  library  writers   How  does  RxJava

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

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

     RxJava  support  Scala  in  parEcular?   •  How  does  RxJava  support  many  JVM  languages?   •  For  RxJava  consumers  (or  prospecEve  consumers)  
  5. 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?  
  6. 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?  
  7. 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  
  8. 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  
  9. 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  
  10. 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  
  11. 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  
  12. Java  Observable   public  class  Observable<T>  {    public  <R>

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

     Observable<R>  map  (            Func1<?  super  T,  ?  extends  R>  f);   }     public  interface  Func1<T1,  R>  {          public  R  call(T1  t1);   }     Observable<Integer>  o  =  Observable.just(1);     o.map(new  Func1<Integer,  String>()  {    @Override    public  String  call(Integer  i)  {                  return  (i  +  3).toString();            }   });  
  14. Java  Observable   Observable<Integer>  o  =  Observable.just(1);     o.map(new

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

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

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

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

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

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

      o.map(new  Func1<Integer,  String>()  {    @Override    public  String  call(Integer  i)  {                  return  (i  +  3).toString();       Observable<Integer>  o  =  Observable.just(1)       o.map  {  i  -­‐>  (i  +  3).toString  }  
  21. Multiple  Language  Support   •  Java        

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

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

     public  <R>  Observable<R>  map(Func1<T,  R>  f);   •  Scala            def  map[R](f:  T  =>  R):  Observable[R]   •  Groovy          def  Observable<R>  map(groovy.lang.Closure<R>  f)  
  24. Scala  support   •  In  order  to  support  Scala  naEvely,

     we  need:   •  Good  interop  between  Scala  funcEons  and  RxJava  core    
  25. 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  
  26. Implicit  conversions   •  We  have:        

       public  <R>  Observable<R>  map(Func1<T,  R>  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?      
  27. Implicit  conversions   •  We  have:        

       public  <R>  Observable<R>  map(Func1<T,  R>  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?      
  28. Implicit  conversions   •  We  have:        

       public  <R>  Observable<R>  map(Func1<T,  R>  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?      
  29. 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  
  30. Extension  methods   •  Implicit  conversion  to  rx.lang.scala.Observable    

        implicit  def  toScalaObs[T](asJava:  rx.Observable[T])  =        new  rx.lang.scala.Observable(asJava)  
  31. 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]  =  ...          ...      }  
  32. 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  
  33. 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  
  34. Scala  value  classes  (SIP-­‐15)   •  Thanks  to  @samuelgrue#er,  @jmhofer

           package  rx.lang.scala        class  Observable[+T]  (val  asJava:  rx.Observable[_  <:  T])        extends  AnyVal  
  35. 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  
  36. 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  
  37. 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<?  extends  String>  s  =  Producer.stream();                    s.subscribe(new  Action1<String>()  {                          @Override                          public  void  call(String  o)  {                                  System.out.println("onNext  :  "  +  o);                          }});}}  
  38. 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<?  extends  String>  s  =  Producer.stream();                  s.subscribe(new  Action1<String>()  {                        @Override                        public  void  call(String  o)  {                                System.out.println("onNext  :  "  +  o);                        }});                  }            }  
  39. Implementation  Strategies   •  All  JVM  languages  supported  by  rx.Observable

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

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

     via  source      public  class  Observable<T>  {          public  <R>  Observable<R>  map(Func1<T,  R>  f);          public  <R>  Observable<R>  map(groovy.lang.Closure<R>  f);          public  <R>  Observable<R>  map(clojure.lang.IFn  f););            }     •  Would  force  consumers  of  RxJava  to  pull  in  libraries  for:   •  Clojure,  Groovy,  JRuby,  Kotlin,  …  
  42. Implementation  Strategies   •  Method  overloads  with  Object  arguments  

         public  class  Observable<T>  {          public  <R>  Observable<R>  map(Func1<T,  R>  f);          public  <R>  Observable<R>  map(Object  f);      }    
  43. Implementation  Strategies   •  Method  overloads  with  Object  arguments  

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

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

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

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

         public  class  Observable<T>  {          public  <R>  Observable<R>  map(Func1<T,  R>  f);          public  <R>  Observable<R>  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)      
  48. Implementation  Strategies   •  Method  overloads  with  Object  arguments  

         public  class  Observable<T>  {          public  <R>  Observable<R>  map(Func1<T,  R>  f);          public  <R>  Observable<R>  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)      
  49. Implementation  Strategies   •  Method  overloads  with  Object  arguments  

         public  class  Observable<T>  {          public  <R>  Observable<R>  map(Func1<T,  R>  f);          public  <R>  Observable<R>  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    
  50. Implementation  Strategies   •  Method  overloads  with  Object  arguments  

         public  class  Observable<T>  {          public  <R>  Observable<R>  map(Func1<T,  R>  f);          public  <R>  Observable<R>  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    
  51. Implementation  Strategies   •  StaEc  bytecode  rewriEng      

         public  class  Observable<T>  {          public  <R>  Observable<R>  map(Func1<T,  R>  f);          public  <R>  Observable<R>  map(Object  f);      }  
  52. Implementation  Strategies   •  StaEc  bytecode  rewriEng      

         public  class  Observable<T>  {          public  <R>  Observable<R>  map(Func1<T,  R>  f);          public  <R>  Observable<R>  map(Object  f);      }  
  53. Implementation  Strategies   •  StaEc  bytecode  rewriEng      

         public  class  Observable<T>  {          public  <R>  Observable<R>  map(Func1<T,  R>  f);      }           rx/Observable.class   Observable<R>   map(Func1<T,  R>  f)   rx/Observable.class   Observable<R>   map(Closure<R>  f)   rx/Observable.class   Observable<R>   map(Func1<T,  R>  f)   Observable<R>   map(Closure<R>  f)   Package  (1)  
  54. Implementation  Strategies   •  StaEc  bytecode  rewriEng      

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

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

         public  class  Observable<T>  {          public  <R>  Observable<R>  map(Func1<T,  R>  f);      }           rx/Observable.class     Observable<R>  map(Func1<T,  R>  f)   Observable<R>  map(Closure<R>  f)    
  57. Implementation  Strategies   •  StaEc  bytecode  rewriEng      

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

         public  class  Observable<T>  {          public  <R>  Observable<R>  map(Func1<T,  R>  f);      }           •  Causes  havoc  on  tools  unless  we  depend  on  all  languages   (scalac,  IDEs,  …)   Observable.class     Observable<R>  map(Func1<T,  R>  f)   Observable<R>  map(Closure<R>  f)    
  59. 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  <R>  DynamicObservable<R>  map(Object  f);      with  an  implementaEon  which  properly  delegates  to            language-­‐specific  adaptors      
  60. 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  <R>  DynamicObservable<R>  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    
  61. 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  <R>  DynamicObservable<R>  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    
  62. Implementation  Strategies   •  Give  up  on  solving  this  in

     the  general  case   •  Instead,  solve  each  language  separately   •  Scala  –  implicit  conversions  and  value  class  
  63. 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  
  64. 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  (????)    
  65. 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)  
  66. 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    
  67. 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  
  68. 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    
  69. 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      
  70. 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?  
  71. 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)  
  72. Iterable[T]   •  scala.collecEon.Iterable[T]   •  Need  to  implement:  

       def  apply[T](func:  Observer[T]  =>  Subscription)  
  73. 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()  =  {}              }          })  
  74. Mapping  onto  Observable[T]   •  scala.uEl.concurrent.Future[T]   •  Need  to

     implement:      def  apply[T](func:  Observer[T]  =>  Subscription)  
  75. 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()  =  {}  }   })  
  76. 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)              }          }      })  
  77. 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!  
  78. 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  
  79. 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    
  80. 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]      
  81. 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    
  82. 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      
  83. Twitter  business  logic   •  case  class  Mention(time,  name,  screenName,

     imageUrl)   •  def  getResponse(uri:  String):    Observable[ObservableHttpResponse]   •  ObservableHttp.createRequest(apacheReq,  client)  
  84. 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)  
  85. 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)  
  86. 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)  
  87. 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()  
  88. 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)  
  89. 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  
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy