ClojureScript Re-frame subscription dereferencing dilemma - clojurescript

What's the best of following approaches?
Outer subscription, early deref
(defn component [msg]
[:p msg]))
(let [msg (rf/subscribe [:msg])]
[component #msg]
Outer subscription, late deref
(defn component [msg]
[:p #msg]))
(let [msg (rf/subscribe [:msg])]
[component msg]
Inner subscription, early deref
(defn component []
(let [msg #(rf/subscribe [:msg])]
[:p msg])))
Inner subscription, late deref
(defn component []
(let [msg (rf/subscribe [:msg])]
[:p #msg])))
When I keep the inner component pure using outer subscription, I can end up with many arguments that need to be passed through deeply nested structure of often unrelated parents. That can easily become a mess.
When I subscribe inside inner component, it becomes impure, losing easy testability.
Also, I wonder if there is an important difference between early and late dereferencing, other than I have to pass reagent/atom when testing the latter.

We'll the answer, as always, is "it depends", but ...
Outer subscription, early deref leads to pure/testable inners. So that could be a good choice when that's important to you. But we don't use this style much.
Outer subscription, late deref we've actively moved away from this style because it produced code which we later found hard-to-understand. BTW, if ever we do pass ratoms/cursors/subscriptions around, we like to put a trailing * on the argument name to make it clear they are a reference-y thing, and not a value.
Inner subscription, early deref is probably the most used, I'd guess. Feels very natural after a while. Perhaps use <sub from LIN
Inner subscription, late deref this works too, but I tend to prefer the variation directly above. There's always a nagging worry that you might forget to add # at the point of use, and that can be an annoying bug to find.

Don't know if this solves your dilemma, but since Re-frame 0.9 you can write #(rf/subscribe [:msg]) wherever you need a value from the subscription. Subscriptions are cached, so creating many using the same path doesn't yield more than one subscription.
More information in this blog article: https://lambdaisland.com/blog/11-02-2017-re-frame-form-1-subscriptions and this Re-frame issue.

Related

eval-str in ClojureScript with public structure as a parameter

My problem requires applying custom logical functions to a structure. Those functions are stored in a database as a string. I have data like this:
(def fruits {:apple {:color "red" :ripe? true}
:strawberry {:color "red" :ripe? false}})
And I have this cond check:
"(some (fn [fruit] (-> fruit val :ripe? false?)) fruits)"
Unfortunatelly I can't get this right even though I tried various approaches:
1)
(cljs/eval-str (cljs/empty-state)
"(some (fn [fruit] (-> fruit val :ripe? false?)) my.main/fruits)"
""
{:eval cljs/js-eval}
identity)
This works yet it yields errors:
WARNING: No such namespace: my.main, could not locate my/main.cljs, my/main.cljc, or Closure namespace "" at line 1
WARNING: Use of undeclared Var my.main/fruits at line 1
Also this approach obviously wouldn't work in advanced compilation.
2) I tried to leverage approach that works in Clojure:
((eval
(read-string
"(fn [fruits]
(some (fn [fruit] (-> fruit val :ripe? false?)) fruits))"))
fruits)
I can't see why this wouldn't work in advanced compilation. Unfortunatelly it simply returns nil every single time.
Is it just me who fails to come up with a solution or is CLJS just not capable of doing that yet?
I suspect your going to have a vary hard time achieving your requirement using
this approach. The big problem is likely going to be due to the way
clojurescirpt needs to be compiled into javascript (using Google closure). You
can probably get it to work doing some clever stuff with externals and using low
level javascript interop and the closure library, but I suspect it will be hard
work.
A couple of alternative approaches which may be worth considering
Store the data in the database in edn format. Using edn, you may be able to
read it into a var and then execute it
Change direction - do you really need to store complete functions or could you
instead define a type of DSL which obtains parameters from the database which
will provide the necessary level of dynamic execution.
Could you have some sort of pre-processing solution i.e. write the function in
clojurescript, but use closure functionality to compile that to javascript and
insert that into the database instead of the raw clojurescript. This would
make the initial storing of the data more complex, but may simplify calling
the dynamic functions at runtime. You could even include some code checks or
validation to reduce the likelihood of code taken from the database doing the
wrong thing.
There are so many risks associated with using totally dynamic code it is almost
never a good solution. Aside from the numerous security issues you have with
this approach, you also have to deal with elegantly handling problems arising
from buggy definitions being inserted into the database (i.e. a buggy function
definition which crashes your app or corrupts data. If you just have to have the
ability to dynamically execute unknown code, then at least edn provides some
additional protection you don't get with eval-str - but really, just don't do
it.
After hours of experiments and struggling with evaluating functions from strings I decided to write DSL.
In database I store string with a map containing these parameters:
:where? - vector containing path to a desired answer.
:what? - answer(s) I'm looking for.
:strict? (optional) - A boolean. If true then answers need to be exactly the same as :what? rule (order doesn’t matter).
Then I just evaluate that simple cljs file. It works both on advanced and none optimization mode.
(defn standard-cond-met? [{:keys [what? where? strict?]
:or {strict? false}}]
(let [answer (get-in answers (conj where? :values))]
(if strict?
(= (sort what?) (sort answer))
(clojure.set/subset?
(set what?)
(set answer)))))

Using atom and future is creating race condition in my Clojure program

I have a web service written in Clojure. It has a simple GET method implemented, which returns back a JSON object representing the router's current position and different time counters.
My code has a bunch of atoms to keep track of time. Each atom represents different activities a machine might be doing at a given time. For example: calibrating, idle, stuck, or working:
(def idle-time (atom 0))
(def working-time (atom 0))
(def stuck-time (atom 0))
(def calibration-time (atom 0))
Towards the end I have a loop that updates the position and time counters every 15 seconds:
(defn update-machine-info []
(let [machine-info (parse-data-files)]
(update-time-counters machine-info)
(reset! new-state (merge machine-info
{:idleCounter #idle-time
:workingCounter #working-time
:stuckCounter #stuck-time
:calibrationCounter #calibration-time}))))
(loop []
(future
(Thread/sleep 15000)
(update-machine-info)
(recur)))
Currently this code runs into race condition, meaning the position and time counters are not updating. However, the Web Service still responses back a proper JSON response, albeit with old values.
Web Service is using Cheshire to generate map into JSON, here my GET implementation:
(defroutes app-routes
(GET "/" [] (resource :available-media-types ["application/json"]
:handle-ok (generate-string (get-machine-information))))
(route/not-found "Not Found"))
Should I be using refs instead of atoms? Am I using future correctly? Is (Thread/sleep 15000) causing the issue, because atoms are async?
Please let me know if you see an obvious bug in my code.
I don't think you can reliably recur inside a future to a loop that's outside the future (not completely sure), but why not try something like this instead?
(future
(loop []
(Thread/sleep 15000)
(update-machine-info)
(recur)))
That way loop/recur stays within the same thread.
Other than that, it's possible that if update-machine-counters throws an exception the loop will stop, and you'll never see the exception because the future is never dereferenced. An agent ( http://clojure.org/agents ) might be better suited for this, since you can register an error handler.
I think what is happening is that the process where you call your futures is terminating before your futures actually execute. For what your doing, futures are probably the wrong type of construct. I also don't think your loop future recor sequence is doing what you think.
There is a lot of guesswork here as it isn't clear exactly where you are actually defining and calling your code. I think you probably want to use something like agents, which you need to setup in the root process and then send a message to them in your handler before you return your response.

om get-props vs get-state

I am trying to grasp the purpose of the two OM functions get-state and get-props. Have a look at the following example:
(defn example [app owner]
(reify
om/IInitState
(render-state [this state]
(println "app-state: " app )
(println "state: " state )
(println "get-props: " (om/get-props owner) )
(println "get-state: " (om/get-state owner) )
(dom/div nil "hello"))))
You will notice that app and state contain exactly what get-props and get-state return, which seems at the first glance pretty redundant.
Now, not all the lifecycle functions (e.g. IWillMount ) pass the state argument, so when you need it in such circumstances, it's obvious that you need to invoke om/get-state to get access to it.
However, for the app-state it looks different to me. You always have the app-state cursor available in all functions since it's a top-level argument of the function, even if you need it in callbacks you can just pass it around. Most examples/tutorials make use of get-state but I can't find an example of get-props. Is get-props redundant? Where would I use it?
And one more thing related to this construct. In React we have props and state, but in OM we have app-state and state (internal state) which confused me when learning OM. Props are passed from parent to child in React, likewise in OM we pass app-state (cursors) to children. Are the following observations valid?
app-state is the OM equivalent of React' props
props is React is just data, while app-state in OM is data wrapped in cursors
this means that OM doesn't have props, only app-state cursors, hence the function get-props really means get-app-state
According to the docs, get-props is mostly (or exclusively) needed in the IWillReceiveProps phase. will-receive-props gets a next-props argument, which contains the future app-state/props. get-props gives you the current app-state/props so that you can compare the two.
From the Om docs for IWillReceiveProps:
In your implementation if you wish to detect prop transitions you
must use om.core/get-props to get the previous props. This is
because your component constructor function is called with the
updated props.
So the rest of the time, get-props isn't necessary because, as mentioned in the question, you have access to the cursor.

Jsonify a Jdbc4Array in Clojure

I want to jsonify the results of a query performed against a Postgres table containing a column of type text[], but the problem is that clojure.data.json.write-str doesn't seem to know how to handle PG arrays:
Exception Don't know how to write JSON of class org.postgresql.jdbc4.Jdbc4Array clojure.data.json/write-generic
Do I have to supply a custom handler, or is there a simpler way?
Just to wrap up, here's what works for me, putting together Jared's answer with the latest clojure.java.jdbc API changes (0.3.0-alpha5 at the time of writing) which deprecate some patterns that are commonly used (e.g. with-query-results).
First define additional handlers for every unsupported types you care about, for instance:
(extend-type org.postgresql.jdbc4.Jdbc4Array
json/JSONWriter
(-write [o out]
(json/-write (.getArray o) out)))
(extend-type java.sql.Timestamp
json/JSONWriter
(-write [date out]
(json/-write (str date) out)))
Then use with-open to perform the JSON encoding while the connection is still open (which is important at least for org.postgresql.jdbc4.Jdbc4Array):
(with-open [conn (jdbc/get-connection db)]
(json/write-str
(jdbc/query {:connection conn}
["SELECT * FROM ..."]))))
I guess this will change as the clojure.java.jdbc API evolves, but for the moment, it works.
It is better to extend IResultSetReadColumn because you are not
required to stay in the scope of with-open
Something along the following is also more concise:
(extend-protocol jdbc/IResultSetReadColumn
org.postgresql.jdbc4.Jdbc4Array
(result-set-read-column [pgobj metadata idx]
(.getArray pgobj)))
Make sure the namespace where this is placed-in is required!
cheshire is good about handling various data types and being extensible (see add-encoder)
It looks like the issue is org.postgresql.jdbc4.Jdbc4Array does not implement java.util.Collection. Try calling getArray before you serialize it.
Edit:
If it is a nested structure, then it might be best to implement a handler. clojure.data.json uses the JSONWriter protocol. You can try something like the following:
;; Note: Pseudo Code
(extend-type org.postgresql.jdbc4.Jdbc4Array
clojure.data.json/JSONWriter
(-write [o out] (clojure.data.json/-write (.getArray o) out)))

Is it good practice for a Clojure record to implement IFn?

Suppose I have a record that is "function-like", at least in the sense that it represents an operation that could be applied to some arguments.
I can make it work as a function by implementing clojure.lang.IFn, something like:
(defrecord Func [f x]
clojure.lang.IFn
(invoke [this arg]
(f x arg))
(applyTo [this args]
(apply f x args)))
((->Func + 7) 1)
=> 8
(yes I know that I've just reimplemented an inferior version of partial.... it's just an example :-) )
Is making a record implement clojure.lang.IFn a good practice or not?
Any pitfalls to this approach?
I'm surprised it doesn't already. Records are supposed to be "a complete implementation of a persistent map". So to answer your question, I'd expect it to be a function of its keys, as a map is; anything else would be quite surprising.
I can not give a direct Yes/No answer, but I can share my experience.
I defined a record implemented clojure.lang.IFn. Implementing IFn was to let me test it through REPL environment easily.
That record was intended to be a Job class, which was going to be processed by a worker. Therefore, I also implemented another interface java.lang.Runnable and a run function.
When I really put the code into integration test, it threw exception. Why?
The worker logic was something like this:
It checked if the Job class is a Callable instance, if so, invoke the call function.
It checked if the Job class is a Runnable instance, if so, invoke the run function.
However, clojure.lang.IFn has already extended Callable and Runnable, so the exception raised because I forgot to implement the call function.