This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-08-21
Channels
- # announcements (1)
- # babashka (39)
- # beginners (91)
- # cider (9)
- # clj-kondo (10)
- # cljsrn (1)
- # clojure (54)
- # clojure-europe (45)
- # clojure-italy (2)
- # clojure-nl (1)
- # clojure-spec (39)
- # clojure-uk (21)
- # clojurescript (7)
- # core-typed (1)
- # cursive (9)
- # data-science (1)
- # datomic (2)
- # docker (3)
- # emacs (11)
- # figwheel-main (11)
- # fulcro (19)
- # java (1)
- # juxt (1)
- # kaocha (68)
- # malli (7)
- # meander (5)
- # off-topic (76)
- # pedestal (1)
- # re-frame (6)
- # reveal (1)
- # rum (2)
- # shadow-cljs (48)
- # sql (6)
- # tools-deps (47)
- # vim (8)
- # xtdb (23)
Why do we need special syntax for JS properties in cljs? Java has attributes and we need no special syntax for them, right?
I am guessing it is because fields and methods seem identical in JS, but I have never seen it explained 🙂
AFAIU, they don't just seem identical, they are identical. So, (.methodName obj)
translates to obj.methodName()
(a method call), and (.-methodname obj)
translates to obj.methodName
(not a call, returns the method itself)
Good to know! Thanks 🙂
In Java, . finds either method or field (method preferred) and .- finds only field
very useful info
What’s the opposite of dissoc
? https://clojuredocs.org/clojure.core/dissoc
assoc
doesn’t quite seem like it, because you have to provide new key/value pairs. I’m looking to keep only certain keys from the map (without having to care about what their current values), while maintaining the order in the map.
Maybe you want select-keys
?
select-keys
actually throws away the order, if you give it an clojure.lang.PersistentArrayMap
(which is ordered). Sorry, should have clarified that part as well.
i.e. it constructs a new map
That’s entirely fair. I’m working on a patch for a certain library that is specifically asking to preserve the order. But I agree with what you’re saying. Order shouldn’t matter, generally, for maps.
I realize I can basically just build up a new array, like this, just wondering if there’s a slightly simpler way: https://github.com/redplanetlabs/specter/blob/master/src/clj/com/rpl/specter/navs.cljc#L108
although, in truth, some testing of small maps with select-keys
suggests that it does preserve the order anyway
or at least, it keeps the order of the keys you have passed, but only recently (i.e. the first example shown here is no longer what I see on 1.7.0): https://clojuredocs.org/clojure.core/select-keys
At some point, I believe for performance there was a change such that maps start as PersistentArrayMaps and change to PersistentHashMaps after the 8th assoc'd element.
(select-keys (apply sorted-map (interleave (range 20) (range 20))) (range 10))
=> {0 0, 7 7, 1 1, 4 4, 6 6, 3 3, 2 2, 9 9, 5 5, 8 8}
for comparator based order something like this would work
(let [inheriting-select-key (fn [map keyseq]
(into (empty map) (select-keys map keyseq)))]
(inheriting-select-key (apply sorted-map (interleave (range 20) (range 20)))
(range 10)))
=> {0 0, 1 1, 2 2, 3 3, 4 4, 5 5, 6 6, 7 7, 8 8, 9 9}
but if you want to maintain insertion ordered maps then you'd need to traverse the whole map and filter for the keys I suppose which could be a performance concern for a library like specterIf you want a sub-map kind of operation that preserves the concrete type of the given map, e.g. PersistentArrayMap or sorted-map, there is nothing in Clojure core lib that does that. It would be a bit fiddly to write one, but not terribly difficult.
using a protocol based approach, right?
It would not be difficult for existing concrete map types built into Clojure, that is. If you pass it some other map type from a 3rd party library, e.g. a priority-map or ordered-map, then there is no 'sub-map' interface/protocol/whatever to make it straightforward to extend a sub-map operation to new concrete map types one at a time, independently.
I suppose you could create your own protocol for this, implement it for the concrete types built into Clojure core, and invite others to implement it for their custom map types.
I suspect that for this particular case, falling back to the behavior of select-key
for non-core map types would be OK
but thanks for confirming the general approach
this is interesting… apparently the cutoff is ten elements, and it hinges on the to-be-selected keys, not the map to select against.
(select-keys (apply sorted-map (interleave (range 20) (range 20))) (range 9))
=> {0 0, 1 1, 2 2, 3 3, 4 4, 5 5, 6 6, 7 7, 8 8}
(select-keys (apply sorted-map (interleave (range 20) (range 20))) (range 10))
=> {0 0, 7 7, 1 1, 4 4, 6 6, 3 3, 2 2, 9 9, 5 5, 8 8}
I will admit to being completely flummoxed by that. the sorted-map
, of course, produces clojure.lang.PersistentTreeMap
in both cases, and the (range n)
produces clojure.lang.LongRange
in both cases. (source select-keys)
doesn’t immediately reveal any reason for the difference in behavior here
hmm, I'm on 1.10.0
and get a different (unordered) answer when picking 9
(select-keys (apply sorted-map (interleave (range 20) (range 20))) (range 9))
=> {0 0, 7 7, 1 1, 4 4, 6 6, 3 3, 2 2, 5 5, 8 8}
The reason is that select-keys starts with a 'normal' PersistentArrayMap {}
and then conj
's entries into it as it finds them in the original map, the cutoff can be seen in the implementation of PersistentArrayMap https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/PersistentArrayMap.java#L205,
if more than 8 keys are asked to be selected then it will pass that threshold and create an (unordered) hashmapah, thanks again, Daniel. I’m on 1.7.0 at this moment which explains why I don’t see this patch
select-keys in clojure.core starts with an empty (not sorted) Clojure map, {}
, and does conj
on it once for each key in the final result. If you do that in Clojure/Java, it starts out as a PersistentArrayMap until it gets somewhere around 8 or 9 keys, IIRC, then the next conj
will return a PersistentHashMap. It has been like that in Clojure since the beginning, modulo perhaps an off-by-one fix somewhere in the last several releases.
Small maps are by default PersistentArrayMap's, because that is fast enough at key lookup by doing a linear search, and probably a bit lower memory utilization than PersistentHashMap
ah yes, that can be clearly seen
(conj {:a 1 :b 2 :c 3 :d 4 :e 5 :f 6 :g 7 :h 8} [:i 9])
=> {:a 1, :b 2, :c 3, :d 4, :e 5, :f 6, :g 7, :h 8, :i 9}
(conj {:a 1 :b 2 :c 3 :d 4 :e 5 :f 6 :g 7 :h 8 :i 9} [:z 26])
=> {:e 5, :z 26, :g 7, :c 3, :h 8, :b 2, :d 4, :f 6, :i 9, :a 1}
Any tips on how to setup honeysql and next.jdbc to handle snake case and kebab case conversions between db and application?
So i can't just set the defaults and use them and instead i must copy and paste or refer to a def at the end of every call?
Look at the docs for next.jdbc/with-options
(also, there are #honeysql and #sql channels for HoneySQL and next.jdbc
/`clojure.java.jdbc` questions, where I'm more likely to notice them than here in beginners because they're lower traffic @U0181TUEAC8)
@seancorfield thanks! I'm sorry for not reading the docs properly 😂
NP. There's a lot of docs 🙂
@seancorfield one more question is it okay to wrap every call to c3p0 pooled next.jdbc in core.async/thread?
@U0181TUEAC8 Trying to do I/O around core.async isn't a good idea in general but I'd have to know a lot more about your code to be able to answer that in any useful way.
Doing the I/O in thread
means you won't block but you could also overwhelm your server and/or your database server since that's an unbounded thread pool I believe.
Asked my colleague, who does a lot more core.async
than I do: he said that, yes, doing DB stuff via core.async/thread
is acceptable as long as your c3p0 connection pool is configured properly (not too large) and "as long as the number of go blocks you create is bounded, and you always blocking on the return of async/thread when you spawn it, then you will only spawn a bounded number of threads"
So, several caveats but it's OK if you're careful.
(frankly, I avoid core.async
as much as possible -- it has some good use cases but a lot of people reach for it when they really do not need it!)
@seancorfield im currently rebuilding my elixir stuff both in clojure with core.async and rust with tokio and evaluating them for use in prod, maybe you could share experience maintaining projects in clojure and resource usage under load?
@U0181TUEAC8 Define "under load". Are you talking about web apps, REST APIs? Most Java web servers use a separate thread per request and that's fine for most production loads.
We use Jetty, in its default embedded configuration, and our REST API and it is fine in production.
We use core.async
in one server because it's based on netty-socketio so the traffic is a) very chatty and b) all continuously connected web sockets, so core.async
matches that sort of pattern. But all our other server processes use plain ol' Jetty.
And we're talking 40+ online dating web sites, with thousands of concurrent users, 24x7, backed by just three Jetty instances.
@seancorfield i was talking about web sockets, rest apis, and background jobs. Thanks about the info!
I would suggest building it without core.async
and see how it performs. The JVM is really well optimized and the normal Jetty-based web server approach can take a surprising amount of traffic without needing much else.
core.async
adds a lot of complexity and it's much more about collaborating processes than concurrency.
Hey team, say I want to create an seq of the function f
over and over, with length n
(->> (range n)
(map (fn [_] f)))
Is there a simpler way to write above?(repeatedly n f )
?
(doesn't quote work for my use-case, because I think repeatedly calls the same function over and over too, and does not accept args
I want to then do something like this:
(->> (range n)
(map (fn [_] f))
(apply comp)
(so this would run (comp f f f..) n timesif it's the same value every time, then repeat
(->> (repeat n f)
(apply comp))
can I ask what is probably a really stupid question... Why when I print to my REPL:
(println "is (" x "," y ") within: (" max-x "," max-y ")")
I get spaces that i don't expect:
is ( 6 , 5 ) within: ( 7 , 5 )
Why am I getting spaces between the text and the values?
e.g.
(let [a "a"]
(println a "bc"))
;=> a bc
?println adds the spaces for convenience so you can do stuff like (println x y)
which I guess is less convenient for your example
@seancorfield there's some interop with clj-new with lein ? like use lein new
to generate a project with a clj-new
template?
I'd like to use this cool-looking Java library at https://github.com/mangstadt/biweekly so I've added :dependencies [[org.clojure/clojure "1.10.0" [net.sf.biweekly/biweekly "0.6.3"]]
to my lein project.clj. It seems to download fine when I kick up lein repl
-- but I have no idea how to use/require/import its objects so I can use them in clojure! I've tried all the variations of net.sf.biweekly that I could think of
@d.ian.b clj-new
can use templates for lein
, boot
, and its own templates. Does that answer your question?
I can use a clj-new
template with lein
? maybe I should ask on #leiningen
but thanks @seancorfield part of the question was answered =D
Leiningen only understands Leiningen templates. Sorry, I thought I'd answered that in the channel.
Boot understands both Leiningen and Boot templates.
clj-new understands Leiningen, Boot, and clj-new templates.
It doesn't make sense for Leiningen to understand a clj-new template (since it would generate a CLI/`deps.edn` project which lein
could not use).
If you use clj-new with a Leiningen template, you will get a Leiningen project (unless the template also contains support for Boot and/or CLI/`deps.edn`).
If you use Boot with a Leiningen template, you will also get a Leiningen project (for the same reason).
If you use clj-new with a Boot template, you will get a Boot project (again, unless the template author has updated it to include support for CLI/`deps.edn`)
There are very few clj-new templates. clj-new has three built-in ones (`app`, lib
, template
) which generate CLI/`deps.edn` projects. https://clojars.org/search?q=artifact-id%3Aclj-template these are all the clj-new templates that exist -- lein new
only looks for */lein-template
, boot new
looks for */boot-template
first then */lein-template
. clj-new looks for */clj-template
, then */boot-template
, then */lein-template
.
Is that a better explanation @d.ian.b?
(I'm really puzzled by your question, to be honest, because it just "doesn't make sense" so maybe you can explain a bit more about what you mean by the question?)
(I'm wondering if you're confusing the actual templates -- on Clojars -- with the generated project created by * new
from the template?)
The most sensible one would seem to be (import '[net.sf.biweekly Biweekly]) but that doesn't seem to work. hyellppp
(and in turn boot-new
can use templates for lein
as well as boot
)
The project generated by a template will use whatever build tool the template's author decides.
it worked! Thank you @jkrasney!