Fork me on GitHub

Should I use let for a single binding or just use def ?


they do entirely different things


def always creates a global var, unlike, for example, in scheme, where define can create local bindings

👍 5

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


need your help to understand that


Despite this page claiming fn is a "special form" it's actually fn* that is the special form and fn is "just" a macro that wraps that special form.


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 🙂

Alex Miller (Clojure team)06:01:35

I would still consider let, fn, etc to be the special forms (and let*, fn* to be implementation details of how the compiler works)

👍 5

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 🙂

👍 5
Lennart Buit06:01:51

I am having some trouble parsing the advice here: 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?

Lennart Buit06:01:28

Isn’t it a desirable property of concat that it is lazy?


It Depends(tm).

™️ 10

Sometimes you need laziness. Sometimes it gets in the way.


Stuart gives several examples of alternatives...

Lennart Buit06:01:03

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.

Lennart Buit06:01:30

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.

Lennart Buit06:01:20

Is that what you are saying?

Lennart Buit06:01:38

(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.

Lennart Buit06:01:17

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...

Lennart Buit06:01:33

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.

Lennart Buit06:01:48

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

Alex Miller (Clojure team)07:01:41

the key thing to avoid is using concat in like a loop/recur to build up a result

Alex Miller (Clojure team)07:01:53

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.

👍 5
Lennart Buit07:01:35

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


auth:add-pin ?


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


my coworker uses prefixes with colons sometimes and i've liked it


@dpsutton oh, : is a valid identifier? That's neat


yeah, prefixing auth: sounds pretty good


his conventions are easy:create-user, etc



➜  home git:(master) ✗ clj
Clojure 1.10.0
user=> (defn add-pin🔒 [] )


unicode is legit

👏 5



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).


the socket repl is something i can point lein repl at, ya?


I think lein repl uses nrepl? which is a more complex REPL client/server

Alex Miller (Clojure team)20:01:07

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.


ok - nrepl would be better, i'm a sucker for tab completion


Unravel/unrepl can provide that completion without nREPL.


And I’m working on nRepl over socket repl


(it loads the compliment library over the wire into the application)


And compliment is what nREPL uses too, under the hood I believe?


awesome, thanks to all of you!


Here's how to have your application start its own nREPL 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)


well, i'm nowhere near that yet, just trying to inspect a couple things in my httpkit server