This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-01-31
Channels
- # aws (1)
- # beginners (70)
- # boot (12)
- # calva (45)
- # cider (45)
- # clara (1)
- # cljdoc (10)
- # cljs-dev (133)
- # clojure (315)
- # clojure-dev (2)
- # clojure-europe (2)
- # clojure-italy (16)
- # clojure-nl (1)
- # clojure-spec (23)
- # clojure-uk (19)
- # clojurescript (48)
- # cursive (11)
- # data-science (5)
- # datomic (18)
- # figwheel-main (3)
- # fulcro (18)
- # graphql (14)
- # jackdaw (1)
- # juxt (1)
- # kaocha (1)
- # off-topic (10)
- # other-languages (3)
- # pathom (2)
- # pedestal (7)
- # re-frame (23)
- # reagent (1)
- # reitit (4)
- # ring-swagger (12)
- # rum (4)
- # shadow-cljs (26)
- # specter (6)
- # speculative (12)
- # tools-deps (44)
- # vim (8)
- # yada (2)
def always creates a global var, unlike, for example, in scheme, where define can create local bindings
i am reading the clojure fn
macro and i saw this symbol fn*
been used but can't find where it has been define or implement
Despite this page claiming fn
is a "special form" https://clojure.org/reference/special_forms#fn it's actually fn*
that is the special form and fn
is "just" a macro that wraps that special form.
@quieterkali See https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Compiler.java#L7103 for where fn*
is handled directly in the Clojure compiler.
That FN
symbol is created here https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Compiler.java#L47
It's similar to how let
is described as a "special form" too but it's actually a macro wrapper around let*
which is built into the compiler.
thank you very much @seancorfield. those links and your explanation helped a lot 🙂
I would still consider let, fn, etc to be the special forms (and let*, fn* to be implementation details of how the compiler works)
Yeah, it's just kind of odd for folks when they run source
on something that is documented as a special form and it prints out regular old Clojure code 🙂
I am having some trouble parsing the advice here: https://stuartsierra.com/2015/04/26/clojure-donts-concat. I understand that if you call concat with long lists/many arguments that there is a risk of StackOverflow, but what is then the ideomatic way to concatenate lists?
Isn’t it a desirable property of concat
that it is lazy?
Sometimes you need laziness. Sometimes it gets in the way.
Stuart gives several examples of alternatives...
Yeah but I don’t understand why I would want that more, I read it like 10 times :’). He uses into
to accumulate into a collection, but thats not lazy at all right
Correct. into
uses reduce
and conj
.
The main thing to bear in mind is, if you find yourself reaching for concat
, just think carefully about how it will be realized -- and whether you really need laziness or not.
righhht, that makes sense. So concat
is not universally frowned upon
As the article says, it can seem like the obvious, simple solution -- and if you're working with small lists or realizing just a single concat
call you'll be fine. But if you're not careful, it can bite you.
Is that what you are saying?
(Sorry my internet left me for a bit, train wifi)
We use it quite a lot at work -- but we're careful about where we use it.
Right thank you, I got a review comment saying that concat
is bad, so I went replacing it with into
, but I kept wondering whether thats also not equally bad because its non-lazy. So, its a pick-your-poison kinda deal
The other thing to watch out for with laziness is that many lazy sequences are "chunked" so you'll get blocks of 32 items realized, rather than just the exact number you might expect...
Yeah so if they are very computationally heavy per element, you have a chance of realising 32 at once, right
For example (take-while #(< % 10) (map #(do (println %) %) (range 100)))
will print 0, 1, .. 31 and then return (0 1 .. 9)
so you get 22 elements calculated that you might not want/expect.
Right, that gets frustrating when you have a lazy-seq finding & realising large prime numbers 😉
Reading over Stuart's article again, and the comments, and I'd forgotten that core.cache
had a bug caused by concat
(mentioned in the comments, and the JIRA issue points back to that article), that was one of the first things I fixed when I took over the library https://github.com/clojure/core.cache/commit/0f7ef2294c76284949e681e4b620f07c7dbc1f06
the key thing to avoid is using concat in like a loop/recur to build up a result
when you say “very computationally heavy per element” above, that should set off all kinds of alarms - this is a case where you want fine-grained control about when things are realized. You should never (well, no absolutes, but rarely) use lazy sequences for something like that, where you inherently give up control over when things are realized. It’s better to use loop/recur with explicit termination conditions for stuff like that.
Right, its much clearer now, thank you both 🙂!
I'm looking to implement some symbol pattern like add-pin*
or similar, to indicate that a function should have passed some sort of authentication beforehand. Anyone have any ideas on characters that can symbolize something like "danger", "pay attention"? Or just suitable characters to use for it?
@victorbjelkholm429 like add-pin!
to indicate there are side effects you need to worry about?
@noisesmith well, already using !
for indicating side-effects
one "trick" is giving it a weird, excessively long and discriptive name, then give the function that does the proper checking before calling it a normal and readable name
but this is the sort of thing where I'd definitely use regular old doc strings and code comments too
even an entry in Readme.md
hm, I see. Yeah, I currently have my db
functions just act directly on the "db", but then provide other functions, basically wrapping the db functions, only actually calling them if authorized correctly. It's those wrapper functions I'm looking to name
➜ home git:(master) ✗ clj
Clojure 1.10.0
user=> (defn add-pin🔒 [] )
#'user/add-pin🔒
user=>
thanks Java!
hi, i'd like to be able to attach a repl to a running uberjar (or something running from lein run
in dev) - is there an example somewhere i could check out? thanks very much!
@hoopes If you just need a Socket REPL, you can start the uberjar up with an additional JVM option that tells Clojure to start a Socket REPL server as it starts the application up.
If you need an nREPL Server, you can start one programmatically (see the nREPL repo for details).
https://clojure.org/reference/repl_and_main#_launching_a_socket_server
not directly (as it’s stream based) but you can use nc
or telnet
to connect to it
You can point unravel/unrepl at a Socket REPL. You can connection Atom (editor) to a Socket REPL via the Chlorine plugin.
Unravel/unrepl can provide that completion without nREPL.
(it loads the compliment
library over the wire into the application)
And compliment
is what nREPL uses too, under the hood I believe?
Here's how to have your application start its own nREPL Server https://github.com/clojure/tools.nrepl#embedding-nrepl-starting-a-server
The nice thing about the JVM option and Socket REPL is that you can even get a Socket REPL into a Java application if it happens to use Clojure for anything internally 🙂
(we have legacy JVM apps that use Clojure libraries and that's how we start a Socket REPL inside them for debugging)