Fork me on GitHub
#beginners
<
2022-04-23
>
Jon Olick00:04:45

Bug in the docs for https://clojuredocs.org/clojure.core/quote If I run the example there (quote 1 2 3 4 5) I get

user=> (quote 1 2 3 4 5)
Syntax error (ExceptionInfo) compiling quote at (REPL:1:1).
Wrong number of args (5) passed to quote

Jon Olick00:04:11

It should be noted that quote shorthand `() works fine.

user=> (quote 1 2 3 4 5)
Syntax error (ExceptionInfo) compiling quote at (REPL:1:1).
Wrong number of args (5) passed to quote
user=> (list 1 2 3 4 5)
(1 2 3 4 5)
user=> '(1 2 3 4 5)
(1 2 3 4 5)

seancorfield01:04:37

It used to work on Clojure 1.5... let me see what other versions it works on...

seancorfield01:04:40

OK, it changed in Clojure 1.8:

$ for v in 1 2 3 4 5 6 7 8 9 10 11; do echo Clojure 1.$v; clojure -M:1.$v -e '(quote 1 2 3 4 5)'; done
Clojure 1.1
user-loaded
1
Clojure 1.2
user-loaded
1
Clojure 1.3
user-loaded
1
Clojure 1.4
user-loaded
1
Clojure 1.5
user-loaded
1
Clojure 1.6
user-loaded
1
Clojure 1.7
user-loaded
1
Clojure 1.8
user-loaded
Exception in thread "main" clojure.lang.ExceptionInfo: Wrong number of args (5) passed to quote {:form (quote 1 2 3 4 5)}, compiling:(NO_SOURCE_PATH:1:1)
        at clojure.lang.Compiler.analyzeSeq(Compiler.java:6875)
...

Jon Olick01:04:23

also docs say that '() is the same as (quote) which is no longer the case

seancorfield01:04:43

I updated the example on that page.

seancorfield01:04:55

(anyone can update examples if they create an account)

Jon Olick01:04:20

yeah, but not a beginner I hope 🙂 I'd probably just screw things up

seancorfield01:04:01

'() has always been () but (quote)` used to be nil (up until Clojure 1.8)

seancorfield01:04:22

$ for v in 1 2 3 4 5 6 7 8 9 10 11; do echo Clojure 1.$v; clojure -M:1.$v -e "['() (quote)]"; done
Clojure 1.1
user-loaded
[() nil]
Clojure 1.2
user-loaded
[() nil]
Clojure 1.3
user-loaded
[() nil]
Clojure 1.4
user-loaded
[() nil]
Clojure 1.5
user-loaded
[() nil]
Clojure 1.6
user-loaded
[() nil]
Clojure 1.7
user-loaded
[() nil]
Clojure 1.8
user-loaded
Exception in thread "main" clojure.lang.ExceptionInfo: Wrong number of args (0) passed to quote {:form (quote)}, compiling:(NO_SOURCE_PATH:1:6)
        at clojure.lang.Compiler.analyzeSeq(Compiler.java:6875)

Jon Olick01:04:37

interesting, ok

seancorfield01:04:53

Where do the docs say (quote) is the same as '()?

Jon Olick01:04:05

;; ' is the shortcut for quote
user> (= 'a (quote a))
true

Jon Olick01:04:23

(= '(1 2 3) (quote 1 2 3)) would fail

Jon Olick01:04:31

probably not even compile

Jon Olick01:04:14

note my example up top of thread

seancorfield01:04:31

You misunderstand the equivalence...

seancorfield01:04:58

'some-form is a reader shorthand for (quote some-form) but that is a singular Clojure form.

seancorfield01:04:59

When things happen in the reader, they happen on a (single) per-form basis.

Jon Olick01:04:06

I could have sworn some docs somewhere said '(1 2 3) is the same as (quote 1 2 3)

Jon Olick01:04:04

I guess '(1 2 3) is more like (list 1 2 3)

Jon Olick01:04:16

thus I got confused

seancorfield01:04:37

(list x y z) will evaluate the arguments, '(x y z) will not

seancorfield01:04:58

Because (quote (x y z)) is (x y z) -- the literal form.

Jon Olick01:04:49

that definitely clears things up

seancorfield01:04:09

user=> (def x 1)
#'user/x
user=> (def y 2)
#'user/y
user=> (def z 3)
#'user/z
user=> (list x y z)
(1 2 3)
user=> '(x y z)
(x y z)

seancorfield01:04:37

and for completeness

user=> (quote (x y z))
(x y z)

👍 1
hiredman02:04:21

Something to keep in mind is http://clojuredocs.org is a third party documentation site with user contributed examples

hiredman02:04:03

It includes the official clojure doc strings, but also a bunch of other stuff

hiredman02:04:13

http://clojure.org is the definitive source, but it is very spare

seancorfield02:04:49

(and they've been contributed over a ten year period, roughly, while Clojure has changed over that time -- while it is mostly backward compatible, and especially so around actual officially documented behavior, there is still a lot of undefined behavior that has changed, usually with undocumented and unintended behavior becoming illegal)

Ben Sless05:04:12

Another way this could be explained - cons is a function. A function evaluates its arguments. lazy-seq is a macro. It does not evaluate its arguments. It emits code. That code is the form, wrapped in a thunk, which is passed to a LazySeq constructor. When you realize a lazy seq the thunk is realized internally.

1
Mobe09:04:24

Not sure where exactly the compiler is failing. It doesn’t say the line number just app.core/eval13726 (NO_SOURCE_FILE:1) Well, basically I’m just trying to pull a path parameter out of the request and return it… I spent the last 2 days figuring out how this can be achieved there’s just no where an easy to follow tutorial

delaguardo09:04:04

You can try evaluating the file form by form to narrow down the search

1
radu14:04:18

int? won't work until you add

{:coercion   coercion-spec/coercion
 :middleware [coercion/coerce-request-middleware]}
options to your router or route

radu14:04:37

you might want to add coercion/coerce-exceptions-middleware for better error messages coercion related

Mobe14:04:18

yap I noticd that only later but I got it working by now… boy there is just way too much stuff to digest

radu14:04:01

reitit is a bit of a beast, but worth learning

Mobe15:04:17

I guess so… I only wish their documents were a bit more hands-on… there is not a single example about extracting path parameters. Now I’m reading up on map deconstruction. I think that is what is going on in the lambda, right?

radu16:04:04

destructuring - but yes, that’s what it looks that you're trying

radu16:04:37

although i'm not sure what you're trying to get at

radu16:04:48

see the “Associative Destructuring” section from https://clojure.org/guides/destructuring

radu16:04:26

there's no need to use :keys for only one key

Mobe17:04:40

there's no need to use :keys for only one key that’s true…. still exploring 🙂 I think I’m getting it

Old account12:04:25

Hello! I heard that pr-str and read-string has bad performance. How about clojure.tools.reader.edn/read-string performance?

teodorlu12:04:33

There's also clojure.edn/read-string

👍 1
1
practicalli-johnny13:04:21

Bad is quite subjective. If function calls are on the critical execution paths and that is not the performance required it is simple to test function performance with https://github.com/hugoduncan/criterium Otherwise,the execution speed of a function may not matter

Old account13:04:22

I understand thanks. Anyway, what is the fastest way to serialize Clojure data structures in ClojureScript? We still can compare how those libs are faster relative to each other.

teodorlu13:04:57

How do you want to read it? #transit is a format designed for fast serialization / deserialization. But it's not human readable.

Old account13:04:48

I only case to pack it and unpack it at another end of the network. It has to be performant.

teodorlu13:04:44

Then it sounds to me that transit is a better match for you then EDN :)

💪 1
teodorlu13:04:34

If you don't need to encode arbitrary clojure data structures, you might find even faster options.

Old account13:04:40

Thanks, everyone for the nice advice. I will test and measure all those options :smiling_face_with_3_hearts:

👍 1
jorda0mega16:04:37

Hello. I have a function that takes in an item and then constructs a query (executed on Postgres db) to get the last_updated flag for this item. I need to get the last updated for multiple items so my idea was to map over a collection items and make a call for each one (map (fn [item] (get-last-updated item)). However, this doesn't seem to work. It is returning nil in the resulting collection. If I call it for one (get-last-updated (first items)) item it gives me the correct timestamp. Anyone know what could be causing this?

didibus17:04:45

It could have something to do with the function. Does it need an environment to work? Like does it need a DB connection to be established first, or something to be setup? Map is lazy, so maybe it escapes the environment and that's why the function returns nil. You could try replacing map for mapv

jorda0mega18:04:30

The connection it might. I tried replacing it with mapv and pmap but same result

didibus18:04:21

I would add a println or something inside get-last-updated, just to be sure it is being called properly

didibus18:04:44

And it be good if you printed the item it receives, so you can see if that works too.

Baye16:04:35

Hi, newbie question: What is the proper use for repl to reap the benefits, especially in say a reagent project? For example: 1. For a normal CLI project, you can evaluate a line of code, a block or a whole file and run the repl...is there more? 2. For clojurescript (say reagent) project, how do you take advantange of the repl? You already have hot-reload type of feature: that is if you change code you can immediately see the changes on the browser. What does the REPL offer in this case? Thanks

didibus17:04:22

Correct, the REPL lets you evaluate arbitrary code and hot-swap existing defs and defns for new ones. This is true in Clojurescript as well, even if you use reagent. Not sure what a function does if you pass it nil ? Just try it in the REPL and see for yourself. Want to inspect some state in your app? Why not look it up in the REPL? Now you're saying you've got hot-reload setup for Clojurescript on save? So I'm assuming you've got figwheel or shadow-cljs setup? Those are effectively more complex REPLs. They use the same underlying principle and technology to hot-reload the app in the browser while maintaining some of the application state between reloads. That's the difference with just refreshing the page. What the REPL also is often used in Clojure and Clojurescript is for your IDE features. It'll often give you auto-completion, jump to definition, ways to inspect thrown error and have the error highlighted where it was thrown on the code. Show the documentation for a function, show the macroexpansion of a macro, etc. So maybe you don't need it, but your IDE might benefit so it can give you all these additional features.

👍 1
Baye18:04:49

yes reagent + Shadow-cljs

Baye18:04:56

Would love to see repl workflow example, preferrABLY ON VIDEO

didibus18:04:24

What editor do you use?

didibus19:04:12

This might show it a little, it is doing react-native with expo, but it shows a bit why the REPL is nice even if it hot-reloads as you save: https://youtu.be/bSi7GpcSsYU?t=309 The REPL bit starts at 5:09

didibus19:04:26

In his case, he's mostly showing to use it for inspection, but he's also getting auto-complete and all other kind of features due to it. And you can use it to explore and experiment with functions and all that as well to learn APIs quickly and test things.

Baye20:04:05

Great! Thanks will check out. I use Cursive

didibus21:04:28

If you use Cursive, you owe it to do one thing. Make a shortcut for eval bound to say Ctrl+Enter or something super easy. I don't know why Cursive doesn't have shortcuts for them by default, but without them, it is really hard to start to use a REPL workflow

didibus21:04:02

Assign yourself easy shortcuts for all the functions mentioned here: https://cursive-ide.com/userguide/repl.html#interaction-with-the-editor

👍 1
didibus21:04:34

Especially: Run form before cursor you want like Ctrl+Enter for that

didibus21:04:52

Oh, and never type in the actual REPL window. Always use those commands that you now have shortcuts for, and you use them when inside the actual source code files.

👍 1
Baye21:04:21

Thanks you so much for all the tips...very helpful!

didibus21:04:01

Ya, so like once you've got your shortcuts, the idea is you can put your cursor anywhere (right after the form) and Ctrl+Enter (say that was your shortcut) and it'll evaluate that form and show the result in the REPL window. You can also reload things by reloading the NS. And I think Cursive doesn't automatically run what you eval in the context of the file. That means you need to use its Switch NS command to switch your REPL to the namespace of the file you are in and then you can Ctrl+Enter into it.

👍 1
Mobe08:04:56

What editor do you use? spacemacs + vscode

Baye13:04:21

i use Cursive