This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-08-12
Channels
- # announcements (5)
- # babashka (1)
- # beginners (193)
- # calva (79)
- # cider (18)
- # clara (4)
- # clojure (38)
- # clojure-europe (12)
- # clojure-france (8)
- # clojure-nl (12)
- # clojure-sweden (1)
- # clojure-uk (50)
- # clojurescript (37)
- # conjure (30)
- # cursive (3)
- # data-science (2)
- # datalog (7)
- # datomic (12)
- # events (2)
- # expound (3)
- # figwheel-main (1)
- # fulcro (45)
- # graalvm (1)
- # jobs (1)
- # jobs-discuss (11)
- # luminus (1)
- # malli (5)
- # off-topic (32)
- # reagent (6)
- # reitit (32)
- # shadow-cljs (25)
- # spacemacs (2)
- # sql (22)
- # vim (6)
Is there a (fast) way to apply
but with the second to last argument expanded instead of the last?
Arguments after the first (the function) are added to the list of args anyway? Do you have an example snippet?
@UHK8B8STX: I want to do something like
(defn foo [& xs] (apply' str \< xs \>))
such that (= (foo 1 2 3) "<123>")
I could do something like
(defn foo [& xs] (str (apply str \< xs) \>))
or
(defn foo [& xs] (str \< (clojure.string/join xs) \>)
…but I don’t want to allocate any temporary stringsLikewise I could do something like
(defn foo [& xs] (apply str (concat [\<] xs [\>])))
but that seems like it’d be inefficient as wellcl-format takes a stream argument which it can output to, which I'd have to check, but might let you avoid unnecessary string creation
I’ve looked at format but not cl-format
Format doesn’t work AFAICT since I’d have to generate the format string
…but the backtick solution seems like it should work (as long as it’s performant enough)! thx
I’d use your early suggestion, but just passing the opening char (not that this is a big deal):
(defn foo [& xs] (apply str \< (concat xs [\>])))
Why? Because the apply
function just uses clojure.lang.AFn/applyTo
and that is going to do the work of getting through the final seqable argument no matter how you handle it. Splicing doesn’t change that.
The str
function then does a recur
to run down that seq and append to a string buffer.The setup of creating a lazy concat
to pick up the final element to go on the end is relatively small, and not going to be a noticeable cost.
If you have a performance issue with that (and I’d be surprised if you did!) then you can just pull apart the str
implementation and append to the StringBuilder
yourself, but I’d be really surprised if you gained any benefit from doing that
When you’re looking to minimize work like that, then the results can be counter-intuitive. It’s worth trying a few million executions of the code in question and timing it. At that point, if you’re unhappy, then it’s worth looking into how it works and see if there is anything redundant happening. (I like to look anyway, just to find out how it works)
If you try (source apply)
you’ll see how it uses the IFn
method applyTo
. That’s at https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/AFn.java#L143
You’ll see that for anything more than 20 values, it creates an array of the data to pass in, and the function should be handling an array parameter by that point anyway. So what you’re passing will go to an array. Doesn’t seem too bad.
Hows does str
manage all these parameters? (source str)
does this in its final arity:
((fn [^StringBuilder sb more]
(if more
(recur (. sb (append (str (first more)))) (next more))
(str sb)))
(new StringBuilder (str x)) ys)
So it just iterates along and uses java.lang.StringBuilder.append(String s)
on every elementThis is one of the things I like about Clojure. It’s very easy to see what’s actually going on
Inspired by quoll, I looked up what the backtick version expands to:
(apply str (clojure.core/seq (clojure.core/concat (clojure.core/list \<) xs (clojure.core/list \>))))
I have a problem with next-jdbc... It suddenly refuses to work properly. No code changes have been made. Reading from the database works fine. But as soon as I use with-transaction
or call a hugsql generated function that would end in a write, I get an
Execution error (ConnectException) at java.net.PlainSocketImpl/socketConnect (PlainSocketImpl.java:-2).
Connection refused (Connection refused)
exception. The role definitely does have write rights from my machine, it is the role I use daily to make changes to the database. Anyone knows what that could be?might want to ask in #sql
hello, in CLJS there is the IFind
protocol to define how a type should respond to find
, is there an analogous one in CLJ?
not really. probably the closest is Associative's entryAt() method
if a type implements Associative, that method will be used
(but there are also special cases in RT.find() for Map and ITransientAssociative2)
I remember some advice that if app.foo.bar
is a namespace, then app.foo
should not be a namespace. does anyone know where I might have read this?
not an issue at all in clojure (and pretty common) but I think there is some issue with this in cljs?
pretty sure thats only CLJS-only advice since app.foo/bar
can clash with app.foo.bar
?
so namespaces are reified into the same "namespace" as the definitions in them? that's weird
I guess that's using js globals, and that's simply the semantics offered?
yeah, plus it has some nice things about it. using closures as namespaces has its own problems…