Fork me on GitHub
#beginners
<
2019-01-31
>
johan17801:01:21

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

hiredman01:01:07

they do entirely different things

hiredman01:01:47

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

quieterkali05:01:04

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

quieterkali05:01:26

need your help to understand that

seancorfield05:01:35

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.

seancorfield05:01:47

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

seancorfield05:01:30

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.

quieterkali06:01:36

thank you very much @seancorfield. those links and your explanation helped a lot ๐Ÿ™‚

alexmiller06: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)

seancorfield06:01:34

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 ๐Ÿ™‚

lennart.buit06:01:51

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?

lennart.buit06:01:28

Isnโ€™t it a desirable property of concat that it is lazy?

seancorfield06:01:12

It Depends(tm).

seancorfield06:01:33

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

seancorfield06:01:14

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

seancorfield06:01:30

Correct. into uses reduce and conj.

seancorfield06:01:23

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

seancorfield06:01:49

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)

seancorfield06:01:45

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

seancorfield06:01:00

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

seancorfield06:01:52

For example (take-while #(< % 10) (map #(do (println %) %) (range 100))) will print 0, 1, .. 31 and then return (0 1 .. 9)

seancorfield06:01:25

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 ๐Ÿ˜‰

seancorfield06:01:09

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

alexmiller07:01:41

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

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

lennart.buit07:01:35

Right, its much clearer now, thank you both ๐Ÿ™‚!

victorbjelkholm42913:01:01

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?

noisesmith17:01:30

@victorbjelkholm429 like add-pin! to indicate there are side effects you need to worry about?

victorbjelkholm42917:01:49

@noisesmith well, already using ! for indicating side-effects

noisesmith17:01:37

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

noisesmith17:01:05

but this is the sort of thing where I'd definitely use regular old doc strings and code comments too

noisesmith17:01:18

even an entry in Readme.md

dpsutton17:01:39

auth:add-pin ?

victorbjelkholm42917:01:45

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

dpsutton17:01:49

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

victorbjelkholm42917:01:58

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

victorbjelkholm42917:01:13

yeah, prefixing auth: sounds pretty good

dpsutton17:01:50

his conventions are easy:create-user, etc

ghadi19:01:20

@victorbjelkholm429

โžœ  home git:(master) โœ— clj
Clojure 1.10.0
user=> (defn add-pin๐Ÿ”’ [] )
#'user/add-pin๐Ÿ”’
user=>

ghadi19:01:36

unicode is legit

ghadi19:01:28

with-๐Ÿ”’

alexmiller19:01:10

thanks Java!

hoopes20:01:46

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!

seancorfield20:01:44

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

seancorfield20:01:10

If you need an nREPL Server, you can start one programmatically (see the nREPL repo for details).

hoopes20:01:26

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

lilactown20:01:04

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

alexmiller20:01:07

not directly (as itโ€™s stream based) but you can use nc or telnet to connect to it

seancorfield20:01:32

You can point unravel/unrepl at a Socket REPL. You can connection Atom (editor) to a Socket REPL via the Chlorine plugin.

hoopes20:01:36

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

seancorfield20:01:54

Unravel/unrepl can provide that completion without nREPL.

cgrand21:01:15

And Iโ€™m working on nRepl over socket repl

seancorfield20:01:10

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

seancorfield20:01:33

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

hoopes20:01:44

awesome, thanks to all of you!

seancorfield20:01:20

Here's how to have your application start its own nREPL Server https://github.com/clojure/tools.nrepl#embedding-nrepl-starting-a-server

seancorfield20:01:56

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 ๐Ÿ™‚

seancorfield20:01:21

(we have legacy JVM apps that use Clojure libraries and that's how we start a Socket REPL inside them for debugging)

hoopes20:01:39

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