This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-08-19
Channels
- # announcements (4)
- # asami (1)
- # babashka (48)
- # beginners (84)
- # bristol-clojurians (1)
- # calva (15)
- # chlorine-clover (11)
- # cider (37)
- # clj-kondo (17)
- # clojure (72)
- # clojure-europe (13)
- # clojure-italy (43)
- # clojure-nl (6)
- # clojure-spec (8)
- # clojure-uk (19)
- # clojuredesign-podcast (7)
- # clojurescript (132)
- # code-reviews (7)
- # conjure (3)
- # cursive (24)
- # datascript (10)
- # datomic (61)
- # docker (4)
- # duct (24)
- # emacs (2)
- # figwheel-main (8)
- # fulcro (43)
- # graalvm (5)
- # juxt (1)
- # keechma (14)
- # malli (2)
- # off-topic (120)
- # re-frame (111)
- # reagent (6)
- # reitit (13)
- # shadow-cljs (118)
- # spacemacs (3)
- # tools-deps (32)
- # uncomplicate (5)
- # xtdb (6)
Hi all, should this happen?
(if (Boolean. "false") "true" "false")
;; => "true"
(= (Boolean. "false") false)
;; => true
@ben.sless never use the Boolean constructor
unlike java, clojure's if
uses an identity check on Boolean/FALSE
rather than checking the value
you can use Boolean/valueOf
in place of the constructor to get the correct result
(or wrap the Boolean constructor call in a call to clojure.core/boolean, but valueOf is more direct)
Thanks @noisesmith, don't worry, I'm not using it 🙂
A colleague asked me that question and I realized I had no idea, so I came here to ask the experts
I probably don't need to go around using the language of a priest about this - of course I mean that there's no case I know of where using the Boolean constructor makes sense in clojure code - there's always a simpler and more correct solution
counter examples or proof of my statement both welcome haha
now we have the pragmatic choice - which wastes more time, looking for a constructive use of the Boolean constructor in clojure code or short circuit assuming that it's never valid 😆
Life needs an element of mystery, I think. Label it under "There Be Dragons" until a brave soul ventures out and returns with a useful answer 😄
But the documentation of if
comes to the rescue:
if
(if test then else?)
Special Form
Evaluates test. If not the singular values nil or false,
evaluates and yields then, otherwise, evaluates and yields else. If
else is not supplied it defaults to nil.
The constructed object may be =
to false
, it prints as false
, but it's not the "singular value[...] false".
Intuitiv? Probably not. Relevant for real life? Neither, I'd say. At least, I've not hit that problem in the past 10+ years.One way in which I think it is relevant for real life is that I am fairly sure that it improves the performance of Clojure code execution for if
to behave as it does, versus also taking the false branch for other values =
to false
Hey, I had a question on destructuring:
(let [{:keys [region]} {:region "x"}]
region)
Could I bind region
to another name, for instance src-region
Perhaps:
(let [{src-region :region} {:region "x"}]
src-region)
?Hi guys, what version of openjdk should I be running? Is there any reason for me not to go from openjdk 8 to 11 ? 😮
Java 11 is a very safe choice for running Clojure. It's been around long enough that any bugs have been fixed. Make sure your build tools are up to date and of course test your apps before changing Java versions in production
I understand that both are LTS versions and from state of clojure https://clojure.org/news/2020/02/20/state-of-clojure-2020 ... > Clojure itself has been using Java 8 as the baseline JVM for a couple years and will continue to do so (while also supporting newer versions of Java). When running Clojure, we recommend Java 8 or 11 right now. So in that sense is perfectly good for me to switch to java 11?
I’ve been running in dev with JDK 14 even and it works well; JDK 11 in prod for a while and no issues. Note that LTS is a concept that only makes sense when talking about particular distributions (in particular Oracle’s Jdk) and their guarantees - you cannot say JDK11 in general is lts
Is there an easy way to use deps.edn :main-opts
where I can say where exactly the command line argument from the user goes?
E.g. I have this in my deps.edn aliases
:uberjar {:extra-deps {seancorfield/depstar {:mvn/version "1.0.97"}}
:main-opts ["-m" "hf.depstar.uberjar" ...USER-ARG-HERE... "-C" "-m" "myapp.core"]}
Then I would just like to call something like clojure -A:uberjar myappUberJar.jar
I guess it would be a good enhancement to allow the JAR file to be specified in any order with the options. Can you create an issue on my depstar
repo on GitHub about that so I don't forget?
@daniel415 Also, what did you think of Alex's suggestion for a -X
entry point? I'm not sure that would be easier for users but it is another option to consider.
Thanks. I created the issue https://github.com/seancorfield/depstar/issues/33
Thanks @daniel415!
I think the map entry point is probably a good idea in general but for my use-case where I want that the user has to type as little as possible nothing beats -A:uberjar xxx.jar
I guess.
Yup. Working on it right now.
@daniel415 that is implemented on *develop* if you want to depend on depstar
via :git/url
and :sha
to test it out.
It will accept the JAR file name and options in any order now. You can also specify the JAR file name with -J
or --jar
if you want 🙂
That was fast 🙂 I just tested it
:uberjar {:extra-deps {seancorfield/depstar {:git/url ""
:sha "c461ba830e069edf0f011169c18595a4a8f917fc"}}
:main-opts ["-m" "hf.depstar.uberjar" "-C" "-m" "myapp"]}
and now I can just do the clojure -A:uberjar myapp.jar
like I wanted. Thanks for the fast help.Thank you for testing that and confirming it works!
no, that's not an available feature
ok, thanks.. I guess I'll just write in the readme that the user has to append the -C and -m options themself 😉
I think #babashka has some sort of uberjar'ing facility...a recent addition I think
Nice. babashka is really cool. But I need a "real" java uberjar und not a bb uberjar. Very nice nevertheless 🙂
Maybe you could ask @seancorfield to make the uberjar name itself also a normal CLI arg
better, I would suggest a map entry point compatible with -X and overrides
@daniel415 Creating an uberjar with babashka that's runnable with Clojure:
borkdude@MBP2019 /tmp $ mkdir -p uberjar/src
borkdude@MBP2019 /tmp $ cd uberjar
borkdude@MBP2019 /tmp/uberjar $ echo "(ns foo (:gen-class)) (defn -main [& args] (prn :hello))" > src/foo.clj
borkdude@MBP2019 /tmp/uberjar $ clojure -m foo
:hello
borkdude@MBP2019 /tmp/uberjar $ mkdir -p classes
borkdude@MBP2019 /tmp/uberjar $ clojure -e "(require 'foo) (compile 'foo)"
foo
borkdude@MBP2019 /tmp/uberjar $ ls classes
foo$_main.class foo$fn__153.class foo$loading__6721__auto____151.class foo.class foo__init.class
borkdude@MBP2019 /tmp/uberjar $ bb -cp $(clojure -Spath):classes -m foo --uberjar /tmp/foo.jar
Building uberjar: /tmp/foo.jar
borkdude@MBP2019 /tmp/uberjar $ ( cd /tmp; java -jar foo.jar )
:hello
The crux: you need to compile the main class yourself with Clojure, since babashka doesn't do compilation
Note: I've just merged the uberjar feature to master, it's not released as of now, but there are pre-release binaries in #babashka_circleci_builds
When we have an atom and we add a watch to it, what happens to the watch if the atom gets garbage collected?
it gets garbage collected too
watches are not active threads, they are side effects triggered on change
even in ClojureScript?
especially in cljs, since there's no extra threads there
Thanks a lot!
I am having newb problems with sente.
I want to push from the client to the server. I send a message in a connected repl with (chsk-send! :sente/all-users-without-uid [:h/h "Hooooo!"])
.
I have two event-handlers on the client side:
(defmethod -event-msg-handler :chsk/recv
[{:as ev-msg :keys [?data]}]
(js/alert (str "Push event from server woop wopp: " ?data)))
(defmethod -event-msg-handler :h/h
[{:as ev-msg :keys [?data]}]
(js/alert (str "correctamundo " ?data)))
It is always :chsk/recv
which receives the message, not the :h/h
one.
This is the alert printed: Push event from server woop wopp: [:h/h "Hooooo!"]
Any guesses what I am doing incorrectly? Am I misunderstanding something? I expect :h/h
to handle it, not :chsk/recv
See thread for info needed to reproduce.Repo is here: https://github.com/endrebak/everflow
git clone [email protected]:endrebak/everflow.git
cd everflow
lein shadow watch app
# new tab
lein run
# new tab
lein repl :connect 7000
(require 'everflow.routes.home)
(in-ns 'everflow.routes.home)
@connected-uids
(chsk-send! :sente/all-users-without-uid [:h/h "Hooooo!"])
IIRC all messages have the :chsk/recv key, other keys are for metadata describing the state transitions of the connection
eg. you'd use them to hook in a callback for when you get a connection, time out a connection, etc.
you want your own "routing" which can just be a cond or a multimethod, inside the recv handler
the repl result you show is consistent with this theory
So I am misunderstanding the use then. I should handle the different cases like you said 🙂 Thanks
this is based on a memory of N years ago when I last used it, but your repl printouts are consistent with this theory
I made a router (like the one ring uses) to handle the messages, if I were implementing it today I'd use multimethods instead
one multimethod for the various types of event, another for the :chsk/recv event
You might be right, but it is a bit weird, because on the server side I successfully have methods like
(defmethod -event-msg-handler :everflow/button
[ev-msg] (println :slightly_smiling_face:?data ev-msg)))
that correctly handle the clicks from this JS code:
#(chsk-send! [:everflow/button "Hooo!"])
this might be a dumb client/server asymmetry - try debugging the two sides separately and using less cljc
(Deleted a message which was incorrect)
You might be right. The official client example has no example of -event-msg-handler
with a different namespace than :chsk/
. I should ask on the issues page :)
i might have made an adaptor in the cljc layer that accounted for the asymmetry, but it was in a closed source library I wrote 5 years ago and no longer have (TBH the idea I'd never look at that code again felt like a relief :D)
Lol, I feel that way about all my code XD Actually, in the wild I find one example of arbitrarily namespaced event handlers on the client side (2014): https://github.com/seancorfield/om-sente/blob/master/src/cljs/om_sente/core.cljs#L120 But another one more or less uses your approach (2016): https://github.com/danielsz/system-websockets/blob/master/src/cljs/demo/core.cljs#L46 I will ask on the issues page 🙂
This seems to be relevant: https://github.com/ptaoussanis/sente/issues/151
By setting the option :wrap-recv-evts?
to false
when calling sente/make-channel-socket-client!
my original code works. Thanks!
nice to know about this feature! @UEENNMX0T I think this also answers your question
This is covered in a line in the 3. ed. Web Development with Clojure book:
The wrap-recv-evs? option specifies whether we want to receive all application messages wrapped in an outer :chsk/recv event. We'll turn this off by passing false so that our client events are structured like our server events.
It does not explain why the server and client isn't symmetric though.In the comments in the source it says it is there just for bkwrds compatibility and will be changed in a future release
I’m new to working with atoms. I need one, because I need to load and unload models from memory in my API (https://github.com/jcpsantiago/sagemaker-multimodel-clj). If a model is already in memory the API needs to reply with a 409
— this means I need to check if the model is already in the atom. If it’s not, my fun must load it.
How do I avoid derefing the atom (`current_model`) to test if model-name
is loaded, and then swap!
ing? The code below makes it possible for the state to change between the if and the swapping, which is far from ideal.
(defn load-model!
[model-name url current-models]
(if (db/loaded? model-name @current-models)
(do
(println (str "Model " model-name " is already loaded!"))
{:status 409
:body ""})
(let [xgbmodel (xgb/load-model (str url "/model.xgb"))]
(swap! current-models conj
{model-name
{:model-name model-name :model-url url :model xgbmodel}}))))
Atom doesn't seem to be a problem here. What do you want to happen if the second load-model!
is called while the first call is being executed?
@UTQEPUEH4 from my understanding the following would happen: request1 checks the atom, model is not loaded so proceeds to swap!
; request2 attempts to deref the atom and waits until request1 finished the swap!
.
I think the issue arises when both requests try to check if the model is loaded, see that it is not and then proceeded to load it -- now there will be two loading attempts. Even though the final result is the same when you look at the atom, the second request should respond with a 409 instead of 200.
Am I thinking correctly? This may also all be moot I don't know :man-shrugging:
If you want the second request to return 409 and not to start loading the model, then you should atomically mark the model-name as "loading" before you start loading the model
I'm curious btw, why do you want the second request to return 409? Why don't you want your requests to be idempotent?
I need to abide by AWS's contract which says that if the model is already loaded into memory the server should reply with 409. It seems letting two requests try to load the model in a race condition would still be fine because the end effect is still the same. Adding the fact it's an edge case, I shouldn't worry too much. Is that correct? Thanks for swap-vaks though, I'll check it out
I don't know if the race condition will be tolerated; perhaps it will, but I'd still avoid it -- it's nicer that way, and should be easy, AFAICS
I can't help but think that the following structure would be a good match: an atom
hash (by name) of future
-s
@UTQEPUEH4 could you elaborate? I don’t know what you mean with an atom hash 😅