Fork me on GitHub
#re-frame
<
2021-11-19
>
Quentin Le Guennec10:11:25

Is there any benifit using reg-sub-raw over reg-sub with input-fn + computation-fn when the computation-fn has to be reactive?

p-himik11:11:52

The main use-case for reg-sub-raw is when you don't need db. reg-sub is just a wrapper that sets up the input functions (one of which provices app-db) and derefs their results for you.

Quentin Le Guennec11:11:29

I see, then it's what I'll use.

isak17:11:58

@p-himik Wouldn't any reg-sub alternative to this be fired more often (from unrelated db changes), and generate more garbage?

(rf/reg-sub-raw
  ::mouse-coords
  (fn [app-db _]
    (let [x-pos (ra/cursor app-db [::x-pos])
          y-pos (ra/cursor app-db [::y-pos])]
      (ra/reaction {:x @x-pos :y @y-pos}))))

p-himik22:11:03

If you have those coordinates served via signal subs then no.

isak23:11:56

Seems like passing them in via signal subs would just shuffle the problem around to other parts of the code, not remove it.

p-himik07:11:29

I don't get what you mean. There will be no extra work done, of any kind. So what is the problem you're talking about?

isak17:11:13

The the extra reg-subs you are talking about would have their function get called anytime any part of the app-db changes, right? So that would be code not necessarily executed in my example above.

p-himik17:11:49

> would have their function get called anytime any part of the app-db changes, right? Yes. And your cursor internals will be re-evaluated just as well - to figure out whether the relevant value has changed. There's no magic, the app-db will be wrapped in deref.

p-himik17:11:58

The relevant part of the cursor implementation:

IDeref
  (-deref [this]
    (let [oldstate state
          newstate (if-some [r reaction]
                     (-deref r)
                     (let [f (if (satisfies? IDeref ratom)
                               #(get-in @ratom path)
                               #(ratom path))]
                       (cached-reaction f ratom path this nil)))]
      (._set-state this oldstate newstate)
      newstate))
Note that #(get-in @ratom path) - that ratom is app-db in your case.

isak17:11:20

Yea I understand that, but do you see how version 2 below would be doing more work?

(rf/reg-sub-raw
  :mouse-coords-1
  (fn [app-db _]
    (let [x-pos (ra/cursor app-db [::x-pos])
          y-pos (ra/cursor app-db [::y-pos])]
      (ra/reaction {:x @x-pos :y @y-pos}))))

(rf/reg-sub
  :mouse-coords-2
  (fn [db _]
    {:x (::x-pos db) :y (::y-pos db)}))

p-himik17:11:27

Your version 2 is broken because db is a ratom there. Also, that is absolutely not what I was suggesting.

isak17:11:29

As long as that subscription is active, the hashmap would need to be created for every app-db change. That is not the case with version 1.

isak17:11:52

Fixed, that was supposed to be reg-sub

p-himik17:11:20

I'll quote myself, with extra emphasis: > If you have those coordinates served via signal subs then no.

isak17:11:41

Yea, and that is still false:

(rf/reg-sub
  ::x-pos
  (fn [db _]
    (js/console.log "Code #1 executed every time app-db changes")
    (::x-pos db)))

(rf/reg-sub
  ::y-pos
  (fn [db _]
    (js/console.log "Code #2 executed every time app-db changes")
    (::x-pos db)))

(rf/reg-sub
  :mouse-coords-2
  :<- [::x-pos]
  :<- [::y-pos]
  (fn [x-pos y-pos _]
    {:x x-pos :y y-pos}))

isak17:11:48

See what I mean?

p-himik17:11:02

In your code, ::x-pos is executed exactly as often as the implementation of (ra/cursor app-db [::x-pos]), with pretty much exactly the same cost. Same for ::y-pos. And your :mouse-coords-2 is broken because the first argument to the handler will be a vector with the values. I still don't see what you mean.

p-himik17:11:24

If you don't believe me, just experiment. If you somehow manage to prove me incorrect, please share the code.

isak17:11:34

Ok you're kind of evading the argument with syntax nitpicks

p-himik17:11:29

I'm pointing them out to not confuse the readers. I believe I haven't missed any points you made. The signal subs above will be evaluates just as often as your cursors. As a consequence of that, the resulting sub will be evaluated just as often as well.

isak17:11:42

I don't think I can convince you here, but just wanted to point out to the person asking the question that what you are proposing has some caveats

p-himik17:11:10

In both approaches, there's exactly the same amount of reactions, exactly the same topography. Even caching is there in both cases - in one case it's Reagent's cursor cache, in the other it's re-frame's subscription cache.

p-himik17:11:55

There are no caveats, except for the need to create extra 2 subs. Which can be a benefit by itself, if you use them elsewhere.

isak17:11:27

It isn't necessarily the same amount of work, it depends on what is in your function

isak17:11:15

So the caveat is if you go the reg-sub route, you need to be careful about what you do in the function. That isn't the case with the cursors, because your function/reaction won't even be executed if the paths have not changed.

p-himik17:11:55

> you need to be careful about what you do in the function In which function exactly? With signal subs, you have 3 of them.

isak17:11:39

In all that will get executed on every app-db change

p-himik18:11:01

That statement is false. Only the signal subs handler will be re-evaluted. The sub that uses the signals and doesn't use the db will not be evaluated if the values returned by the signal subs are unchanged. That has nothing to do with re-frame. That's just how Reagent and its reactions work.

isak18:11:06

Yea that doesn't contradict what I said, read carefully

p-himik18:11:14

> In all that will get executed on every app-db change The :mouse-coords-2 sub handler will not be executed on every app-db change.

isak18:11:12

Right. You said in which function exactly? And I said (in code) (filter gets-executed-on-every-app-db-change? functions)

isak18:11:48

It should be clear from the console.logging I added, no? Notice how the one you are objecting to does not have that logging, unlike the other 2.

p-himik18:11:42

I see what you mean. But you never indicated that you understand why your initial claim is incorrect, so I was still discussing the issue from that perspective.

isak18:11:53

You haven't shown any of my claims to be incorrect, just wrong syntax in some of the examples. Anyway I need to get back to work, so I'll have to leave it there.

isak17:11:58

@p-himik Wouldn't any reg-sub alternative to this be fired more often (from unrelated db changes), and generate more garbage?

(rf/reg-sub-raw
  ::mouse-coords
  (fn [app-db _]
    (let [x-pos (ra/cursor app-db [::x-pos])
          y-pos (ra/cursor app-db [::y-pos])]
      (ra/reaction {:x @x-pos :y @y-pos}))))