This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-02-14
Channels
- # announcements (7)
- # babashka (13)
- # beginners (98)
- # biff (20)
- # calva (3)
- # clj-kondo (5)
- # clj-otel (6)
- # cljs-dev (96)
- # clojure (22)
- # clojure-austin (29)
- # clojure-conj (4)
- # clojure-europe (53)
- # clojure-nl (2)
- # clojure-norway (63)
- # clojure-uk (3)
- # clojurescript (18)
- # cursive (10)
- # data-science (11)
- # datalevin (2)
- # datomic (7)
- # deps-new (1)
- # fulcro (3)
- # graphql (1)
- # gratitude (4)
- # hyperfiddle (43)
- # kaocha (4)
- # malli (15)
- # pathom (6)
- # polylith (2)
- # reagent (3)
- # reitit (2)
- # releases (6)
- # remote-jobs (1)
- # rewrite-clj (45)
- # ring (4)
- # shadow-cljs (47)
- # sql (5)
- # xtdb (8)
I have an array of objects, which have :group_id as keys inside, and want to separate them based on :group_id. I did this: (sseq (group-by :group_id array))
,
Now I want to run a function that returnsa component for each item, like this is my result: ([1 [:name "Name 1" :group_id 1] [:name "Name 2" :group_id 1]], [2 [:name "In group 2" :group_id 2]])
I want a map that goes over them, and returns a component of divs containing the names, each group by itself.
I have an array of objects which have :group_id as a key, I did
> I have an array of objects, which have :group_id as keys inside Do you mean you have a vector of maps? Like this:
(def data [{:group_id 1, :name "One"}
{:group_id 1, :name "Uno"}
{:group_id 2, :name "Two"}])
> Now I want to run a function that returnsa component for each item
Since you are talking about components and divs, are you building a web application? What library are you using?
What “item” are you referring to? When you use group-by
, you will get a map of vectors, keyed by the :group_id
. Do you want to create a component for each group?Something like this?
(for [[group members] (group-by :group_id data)]
[:div
[:span "Group ID: " group]
[:ul
(for [{:keys [name]} members]
[:li "Member: " name])]])
Are you using Hiccup? Reagent? Something else?
Then this should work, but don’t forget that you need a :key
for each item when you loop in React
(->> data
(group-by :group-id)
(map-indexed (fn [i [group-id members]]
[:div ,,,])))
I think I would split your problem into three components/functions, so that you have one component for the group and one for the member.
Sorry its not working.. maybe Im missing something. The whole reason I wrote in beginners is Im new to it..
Can you please write it like before in details so that I make sure it works and go with it?
(map-indexed
(fn [i [group-id members]]
[:div {:key i}
[:span "Group ID: " group-id]
[:ul
(map-indexed
(fn [k {:keys [name]}]
[:li {:key k}
[:span "No. " k " - " name]])
members)]])
(group-by :group-id data))
(If you're a beginner why would you want to start with reagent? The web has many moving parts, perhaps try something simpler, make a tictactoe game or something to learn the language first)
@U03KB1C9N8M — is that example clear to you? It is probably important that you do understand the syntax, for
, map-indexed
, and how the examples here use them.
What’s your code?
Does it contain the edited group-by
?
How does your data look?
I think it is important that you divide and conquer. Split your problem into smaller ones.
I did run the code:
(let [data [{:group-id 1, :name "One"}
{:group-id 1, :name "Uno"}
{:group-id 2, :name "Two"}
{:group-id 3, :name "Three"}
{:group-id 3, :name "Tres"}]]
(map-indexed
(fn [i [group-id members]]
[:div {:key i}
[:span "Group ID: " group-id]
[:ul
(map-indexed
(fn [k {:keys [name]}]
[:li {:key k}
[:span "No. " k " - " name]])
members)]])
(group-by :group-id data)))
Output:
([:div
{:key 0}
[:span "Group ID: " 1]
[:ul ([:li {:key 0} [:span "No. " 0 " - " "One"]] [:li {:key 1} [:span "No. " 1 " - " "Uno"]])]]
[:div {:key 1} [:span "Group ID: " 2] [:ul ([:li {:key 0} [:span "No. " 0 " - " "Two"]])]]
[:div
{:key 2}
[:span "Group ID: " 3]
[:ul ([:li {:key 0} [:span "No. " 0 " - " "Three"]] [:li {:key 1} [:span "No. " 1 " - " "Tres"]])]])
hey, I can't figure out how to make sessions work in ring. I have something really simple right now:
(defn foo-handler [req]
(let [session (:session req)
session (assoc session :credentials "secret")]
(-> (redirect "/bar")
(assoc :session session))))
(defn bar-handler [req]
(let [session (:session req)]
(html [:div
[:p "hello from bar!"]
[:p (str "session is: " session)]])))
(defroutes app
(GET "/foo" request (foo-handler request))
(GET "/bar" request (bar-handler request))
(compojure.route/not-found (html [:p "Page not found"])))
(defonce server (atom nil))
(http.server/run-server #'app {:port 8080})
I tried debugging it, and it seems like I'm returning a correct map from foo
. somehow, though, :session
gets lost somewhere before getting to bar
- in the request bar
sees, :session
is nil. how come?compojure doesn't know about session out of the box. you need some middleware that can handle mutable session store to persist data between requests. https://ring-clojure.github.io/ring/ring.middleware.session.html this comes with ring library and can handle simple case
normally you have a middleware that persist the session and set the session key in the cookies, so that the second request works
ohhh I need to plug in the middleware. knew that I was missing something basic. thank you! :)
How can I terminate a function in the repl (say run-jetty for example) without losing the repl?
if there is a function that doesn't return, you can run it in a background thread (using future
or similar)
I'm not sure where run-jetty is from, but lots of http servers have knobs not to tie up the foreground thread
https://stackoverflow.com/questions/2706044/how-do-i-stop-jetty-server-in-clojure
You can terminate, stop start the jetty process without killing the repl very easily. Ideally a reference to the server process should be created. This reference can be used to stop the jetty server. This can be done as a separate expression https://practical.li/clojure-web-services/app-servers/simple-restart.html Or using an atom to hold the reference https://practical.li/clojure-web-services/app-servers/atom-based-restart.html Or when there are multiple components, then use mount, integrant, donut or one of the other lifecycle libraries
@U05254DQM The procedure in your first link doesn’t seem to be working the way I expect. My repl is still blocked, whether it’s the terminal repl or my editor’s connection to the nrepl.
(defn -main [& [port]]
(when-not nrepl (start-nrepl))
(run-jetty
(-> handle-dump
(ring.middleware.file/wrap-file "static")
wrap-proxy)
{:port (or port 8080)}))
@U032EFN0T33 see what i wrote
Jetty keeps the process, so the repl promt is blocked. Use :join? false
as an option
This option returns the process control back to the REPL prompt. This option is in both examples shared
ah so it is. Thanks.
Can I define a function in another namespace using defn “directly”, without changing namespace first?
Yes, but my goal is to add a convenience method to a 3rd party library.
(for use in a particular script of mine)
you can with intern
(but not with defn
) - but I agree with Ghadi this is generally not advisable
In this case, I’m doing this mainly because it’s essentially a “missing method” from this library. It’s one of many others that all act in the same manner. I also plan to PR it once I’m certain.
Thanks though - confirming what I was seeing, I just wasn’t sure if I was missing some way.
Not sure it's a good idea, but you could use something like https://github.com/clojure/clojure-contrib/blob/a6a92b9b3d2bfd9a56e1e5e9cfba706d1aeeaae5/modules/with-ns/src/main/clojure/clojure/contrib/with_ns.clj#L20
(defmacro with-ns
"Evaluates body in another namespace. ns is either a namespace
object or a symbol. This makes it possible to define functions in
namespaces other than the current one."
[ns & body]
`(binding [*ns* (the-ns ~ns)]
[email protected](map (fn [form] `(eval '~form)) body)))
(with-ns 'user
(defn foo [])) ;; #'user/foo
That’s funny, I also had “with-ns” on my brain - primarily because elisp tends to use this pattern with a lot of things.
For your particular use case, I usually clone the repo locally and use the library as a local dep. For my setup (emacs+cider), that let's me jump to namespace and edit/evaluate the code normally. When I'm ready, I can then submit a pull-request upstream.
Yeah, I will get to that as well. This was just some first testing and I was surprised that I couldn’t intern or def it directly.
I have a server up and running with jetty. Right now if something goes wrong in my route handler, I can't see it in the cider repl or nrepl. How do I see this information (runtime errors)?
depends, but absent other factors errors are likely being printed out to the stdout or stderr (I forget which) of the java process
there are ring middlewares that do things like render the error as html and send it as the http response https://github.com/ring-clojure/ring/blob/master/ring-devel/src/ring/middleware/stacktrace.clj#L108-L122
there are also things people do (and maybe something you can setup in cider, not sure) that will try and redirect System/out (by default the jvm processes stdout) to output in the repl
Having a custom type, how can I define equality comparison?
As in is there a way of extending =
to work with my type?
Something like (= person-obj1 person-obj2)
I'm still rather confused about all these, but it seems to me that =
is not a multi-method, so is there no way of extending it then?
Then how do you guys compare custom objects?
(deftype Foo [x]
Object
(equals [this other]
(cond (identical? this other) true
(instance? Foo other) (= x (.x other))
:else false)))
(= (->Foo 3) (->Foo 4))
(= (->Foo 3) (->Foo 3))
Thanks @U11BV7MTK.
How can I found about these though?
If I go to https://clojuredocs.org/clojure.core/= this is not mentioned.
There are other overrides like this toString
for str
etc, but how do I find out about them, is there any list? As it doesn't tend to be in the docs.
The Clojure way is to not use types, but to use maps (just data). (= {...} {...}) will work
(doc =)
-------------------------
clojure.core/=
([x] [x y] [x y & more])
Equality. Returns true if x equals y, false if not. Same as
Java x.equals(y) except it also works for nil, and compares
numbers and collections in a type-independent manner. Clojure's immutable data
structures define equals() (and thus =) as a value, not an identity,
comparison.
OK thanks.
clojure web site doc issues / gaps welcome at https://github.com/clojure/clojure-site/issues
https://clojure.org/reference/datatypes should cover this better
@U064X3EF3 thanks, I'll read up on that and see if I can report an issue.
i know micro benchmarks are just a game and "don't optimize until your application is actually slowing down", but on the other hand... if I am going to access a value from a hashmap multiple times, is it better to assign in a let block and reference the binding or to just use the keyword to access every time?
I always find the best way is to measure.
Wrapping an expression with the (time ,,, )
function will give a very rough guide and quickly pick out the largest disparities in time
https://clojuredocs.org/clojure.core/time will produce more consistent results for an expression
I always use a let block rather than destructure the same thing multiple time, but for cleaner code (usually) than for performance concerns
you aren't talking about micro benchmarks. likely the compiler will optimize this issue you describe, but your code will be worse off in terms of maintenance and readability. a lookup in a hash map doesn't tell you much, so you should document that, and an easy way of documenting something like that is to give it a name.
If I use a hash map value multiple times in a block of code, I'll tend to lift that out as a local binding but not for performance -- for readability, in terms of saying "this particular key value is important enough to this block of code that I'm giving it a name".
Yeah, I tend to prefer it too. Just had the stray thought and couldn't figure out a way to test it in isolation
If you happen to access the same value multiple times but it really isn't important that you're doing that, don't bother putting it in a let
-- it is just noise at that point.
It certainly isn't worth timing it or persuading yourself you're doing it for performance reasons 🙂
Repeated whole subexpressions that take a non-trivial amount of time to compute? Sure, evaluate them once and give them a name. Repeated (:k m)
expressions? Not worth it unless naming them is actually important/useful.
This will not be a performance issue, @UEENNMX0T, just a readability issue.
As for the let
, don't forget destructuring like {:keys [frequent-ref other-ref ....]}
, especially if the map is a function parameter. In the latter case, we can avoid the let
and the noisy repeated access.
btw, this rocks for profiling: https://github.com/ptaoussanis/tufte
It depends on your problem domain. If your performance budget is measured in hundreds of NS, then worry about it. Otherwise worry about readability. The longer answer is that lookup has a few ns overhead, depending on the lookup method and target. There's also the issue of call site polymorphism which affects JIT optimization
is it possible to specify a java ThreadGroup for threads created through calling future
? I was trying to profile my little program to ensure that threads were being closed but it is difficult to tell what thread is the right one to look at.
I see. I'm not super familiar with the java thread model. I've got some reading to do.
I am writing a little socket server currently, and I have a start
function that returns a future
. The body of the future loops and checks a running?
flag to determine whether or not the socket continues to accept connections (and the thread does not go back to the JVM). It doesn't feel very good to write because the future body is creating a closure with the stateful arguments to this start function.
(the stateful arguments being a map within which is where actual SocketServer object gets placed)
I wouldn't use Thread Groups for that anyway. You can simply set a name for a given thread when the future starts. We use something like this in our code to give threads a meaningful name while a block of code is executed
(defmacro with-thread-name-suffix
"Appends `thread-name-suffix` to the current thread name (separates them with \"___unix-time-millis_<currentTimeInMillis>__\"),
executes the body, and then restores the original thread name.
This can be useful for debugging - by temporarily setting thread name to something meaningful."
[thread-name-suffix & body]
`(let [current-name# (.getName (Thread/currentThread))]
(.setName (Thread/currentThread)
(str current-name# "___unix-time-millis_" (System/currentTimeMillis) "__" ~thread-name-suffix))
(try
[email protected]
;; restore the original thread name
(finally (.setName (Thread/currentThread) current-name#)))))