4

I am trying to understand how to structure my program to use RX in a performant matter.
My app has a vector of objects in the 3D world. each object occupied a box, and have a 'hit' stream, which represent a mouse hover over it.
I thought of two options of how to structure:

Option 1

struct object_t
{
  string name_;
  box bounding_box_;
  observable<bool> hit_;
};

struct scene_t
{
  scene_t(observable<point> mouse) : hit_(hit(mouse)) 
  {
    add({"background", {/* ... */}, {}};
  }

  object_t& add(object_t o)
  {
    int object_index = objects_.size();
    o.hit_ = hit_
             .map([=](int index){ return index == object_index; })
             .distinct_until_changed();
    objects_.push_back(o);
    return objects_.back();
  }

  //! given a stream of mouse points,
  //! calculate on which object index(in objects_) the mouse is hover over. 
  //! 0 if its over the background. 
  observable<int> hit(observable<point> mouse);

  using objects_t = std::vector<object_t>;
  objects_t objects_; 
  observable<int> hit_
};

Option 2

struct object_t
{
  string name_;
  box bounding_box_;

  void signal_hit(boot is_hit) { hit_.get_observer().on_next(is_hit); }

  observable<bool> hit() const { return hit_.get_observable(); }

private:
  subject<bool> hit_;
};

struct scene_t
{
  scene_t(observable<point> mouse) : hit_(hit(mouse)) 
  {
    add({"background", {/* ... */}, {}};
    hit_
       .start_with(0)
       .buffer(2, 1) // take two hits together, the current and the previos
       .subscribe([this](std::vector<int> indices) {
          objects_[indices[1]].signal_hit(false); // we leave this one 
          objects_[indices[0]].signal_hit(true); // and entering this one
        });        
  }

  object_t& add(object_t o)
  {
    objects_.push_back(o);
    return objects_.back();
  }
  //! ... as above
};

Now the question is how to chain the result of the hit function to the object_t::hit stream.
I see two ways:

  1. Option 1, is fully functional, but very poorly performing, since for every mouse point, all objects stream will need to calculate their value.
  2. Option 2. is not fully functional, as I use subject to push the values to the right stream, in an imperative way. but is very performant as only the right (two) object(s) hit stream get to fire.

Note: The implementation is in rxcpp, but its general to any language we have RX in it, or general FRP paradigm, this is why I tagged rxjs\rx.net\frp etc.
thanks in advance :-)

ShaulF
  • 591
  • 6
  • 13
  • Not sure what you are asking for: You already state yourself, that Option 2 is performing better - so why wouldn't you want to you this method? I stumbled upon this question because of "rxjs" ... but from what I can tell you there is, that it all depends on the case, there is and will never be that "one perfect solution", besides there are quite some differences in patterns and practices between JS and cpp, so I'd suggest to remove that rxjs-tag as i doubt that anything helpful will come out of it. – olsn Jul 23 '17 at 15:43
  • I am asking exactly that, "How in FRP paradigm, this problem should be solved?". I believe that FRP shouldn't be that inefficient, and need its functional style to be break, in order to achieve performance. I think that people that work with FRP in any language, must have faced such problems, and may have another solution other than the two I presented. If you think I need to translate the code to RxJS in order to ask this community's help, I will be happy to do so. Thanks for your input. – ShaulF Jul 23 '17 at 20:41
  • Probably the best way would be to make it language-agnostic and use those little stream diagrams `----1-----2------3---4-5---|` in combination with pseudo-code - but I understand now where your question is coming from – olsn Jul 24 '17 at 06:27

1 Answers1

0

If there is one source observable and N subscribers then there will have to be at least N computations every time the source emits. There is no way around that which I can think of.

Pace
  • 33,215
  • 10
  • 99
  • 130
  • There is only one hit(hover) stream at a time, so only two subscribers need to be signaled, the one we leave and the one we just hit(start hover over). There are N objects, but, as the problem defined, they don't need to be computed every time. – ShaulF Jul 24 '17 at 21:43
  • I agree. You don't need more than N operations if you have multiple sources. However, the way observables work, if you have one source, and it emits, it will do work for each subscriber. – Pace Jul 25 '17 at 02:40