Fork me on GitHub
#beginners
<
2022-03-30
>
mister_m00:03:55

I have a database connection pool I am messing around with in the REPL. Is there any sort of sophisticated way to view active resources such as a database connection pool or open files, etc etc, beyond inspecting things namespace by namespace? I'm finding keeping track of what is in the REPL quite difficult.

mruzekw00:03:17

You could use something like Integrant to orchestrate each and their dependencies. Then you can initialize and destroy them as you like. I'm sure there's a “check state” function

mruzekw00:03:03

From the looks of it, it might store the state of the of each component on metadata of the config map

Godwin Ko00:03:37

I’d rather choose a proper component management library, e.g. integrant, mount, component or clip, instead of just storing the component state in metadata :thinking_face:

Godwin Ko00:03:04

the concept of https://github.com/weavejester/integrant is interesting and worth take a look, instead of just an service component management tool, it can be used as a general dependency injection micro-framework

mruzekw00:03:48

Right. I'd use Integrant as well. I was just describing how it works internally

1
mruzekw00:03:35

Integrant places metadata on the config map

1
Jon Olick01:03:59

so for loops aren’t actually loops?

Jon Olick01:03:11

they are just kind of ways of making sequences programatically?

Jon Olick01:03:49

and it stores the output of each iteration of the loop in the output sequence

👍 1
quoll02:03:10

Depending on your purpose. If you're generating a sequence, for If you're accumulating a value, reduce If you're just iterating for a side effect, doseq If you don't know when you're going to finish, loop/`recur` Of course, every case is different, so there are no hard and fast rules. But I generally prefer to focus on clojure.core functions before loop/`recur`

🙌 1
quoll02:03:47

Oh, and generally, map rather than for

quoll02:03:51

for is ideal for creating a flat sequence generated by a nested loop.

djblue02:03:35

Much better answer than I provided 😅, thanks 🙏

craftybones02:03:18

There are many looping constructs. A few more

craftybones02:03:28

dotimes if you want to repeat the same thing n number of times

craftybones02:03:08

while a typical while loop that lets you repeat code with side effects

craftybones02:03:42

iterate if you want f(f(f(f(x))))) any number of times

West03:03:13

This is beautiful. Imma add this to my notes.

Jon Olick02:03:44

I don’t quite understand the placement effects of :while and :when

Jon Olick02:03:52

like always at the end makes sense

Jon Olick02:03:59

in the middle is not clear what its doing

quoll02:03:32

It's useful for cutting an outer loop rather than an inner loop. (for [x (range 5) y (range 5)] [x y]) generates coordinates from 0,0 to 4,4. (for [x (range 5) :when (odd? x) y (range 5)] [x y]) Only generates for x of 1 and 3. It doesn't even try to run y from 0-4 for the unwanted even values of x. If the :when were at the end, then the output here would be the same, but the inner loop would run right through 0-4 for the unwanted values of x (i.e. twice the work)

quoll02:03:21

Sorry, I typed all of the above on a phone. I just got on a computer, and see that the conversation has moved on, but I still don't think the :when was considered fully. But here's my example:

quoll02:03:35

(for [x (range 5) y (range 5)] [x y])
Gives you:
([0 0] [0 1] [0 2] [0 3] [0 4] [1 0] [1 1] [1 2] [1 3] [1 4] [2 0] [2 1] [2 2] [2 3] [2 4] [3 0] [3 1] [3 2] [3 3] [3 4] [4 0] [4 1] [4 2] [4 3] [4 4])
If we filter by (odd? x) then we see:
(for [x (range 5) :when (odd? x) y (range 5)] [x y])
([1 0] [1 1] [1 2] [1 3] [1 4] [3 0] [3 1] [3 2] [3 3] [3 4])

(for [x (range 5) y (range 5) :when (odd? x)] [x y])
([1 0] [1 1] [1 2] [1 3] [1 4] [3 0] [3 1] [3 2] [3 3] [3 4])
Same, right? So now, let's put a side-effect into the range for y and see how it gets called...
(for [x (range 5) y ((fn [] (println "\nx=" x) (range 5))) :when (odd? x)] [x y])
(
x= 0

x= 1
[1 0] [1 1] [1 2] [1 3] 
x= 2

x= 3
[1 4] [3 0] [3 1] [3 2] [3 3] 
x= 4
[3 4])
(Sorry the output is messy) Notice how x appears for all 4 values? Now let's filter before the y:
(for [x (range 5) :when (odd? x) y ((fn [] (println "\nx=" x) (range 5)))] [x y])
(
x= 1
[1 0] [1 1] [1 2] [1 3] 
x= 3
[1 4] [3 0] [3 1] [3 2] [3 3] [3 4])

brendnz07:03:58

Cool! That's really helpful for a beginner like me.

👍 1
emccue02:03:12

doseq is closer to your standard "for-each" loop

1
Jon Olick02:03:40

it only applies to the variable immediately preceding it?

emccue02:03:55

but loop combined with recur is your general purpose tool

Godwin Ko02:03:57

that’s why https://clojuredocs.org/clojure.core/for stated that, it is list comprehension

Godwin Ko02:03:44

and it always return a list, even an empty one if nothing to comprehend

Jon Olick02:03:42

for [x (range 3) :when (> x 2) y (range 3) :when (< y 1) ]

Jon Olick02:03:45

kind of same as

hiredman02:03:03

(for [a (range 10)] (inc a)) = (map (fn [a] (inc a)) (range 10))

Jon Olick02:03:27

for(int x = 0; x < 3; ++x) if(x > 2) for(int y = 0; y < 3; ++y) if(y < 1) { do something}

Jon Olick02:03:58

(coming from C/C++ here)

emccue02:03:20

if the do something is "add it to a collection", then yes

emccue02:03:31

but with the caveat that for is lazy

emccue02:03:35

so if you do this

Jon Olick02:03:46

docs don’t say its lazy

emccue02:03:20

(def stuff (for [a (range 100)]
             (do (println "abc")
                 a))))

emccue02:03:34

you don't know how many times that println will be called

emccue02:03:49

it will be called all 100 once you "realize" the full sequence

hiredman02:03:51

(for [a (range 10) b (range 11)] (+ a b)) = (mapcat (fn [a] (map (fn [b] (+ a b)) (range 11))) (range 10))

Jon Olick02:03:58

yeah I understand if its lazy

emccue02:03:59

but clojure's lazy sequences are "chunked"

Jon Olick02:03:02

but docs don’t say lazy

emccue02:03:09

>

and yields a lazy sequence of evaluations of expr.
>

hiredman02:03:14

I would avoid drawing any equivalency between a for loop and a for list comprehension

Jon Olick02:03:26

in the middle there

emccue02:03:36

yeah its in a dense space so its easy to miss i guess

emccue02:03:51

its purpose is different than a C/C++ for. Its just for transforming a sequence of data and getting a new sequence out.

hiredman02:03:51

A list comprehension is a basically a dsl for composing list processing operations (map, mapcat, filter, etc) to build a new list from some given lists

hiredman02:03:23

Similar to set builder notation in math

emccue02:03:09

un`for`tunate naming to be sure

Jon Olick02:03:27

yeah, it probably should have a better name than for

Jon Olick02:03:33

but, its way too late for that

Jon Olick02:03:37

ship sailed a long time ago

hiredman02:03:47

The key thing to understand with for, is the order of clauses in the dsl determines how they would be nested when but from map, filter, and mapcat

hiredman02:03:58

And nesting determines variable scope

Jon Olick02:03:14

sure, just like let

Jon Olick02:03:53

I just have to re-implement this functionality in C so I’m trying to understand it completely

hiredman02:03:04

If you have implementations of map, filter, and mapcat the easiest thing is to have the for macro expand into those calls

Jon Olick02:03:38

don’t think I did mapcat yet, but the others I have

Jon Olick02:03:48

working my way through the spec

Jon Olick02:03:24

I first read the for description and I was like… yeah I’m gonna do this later. And here we are

Jon Olick02:03:48

(for (x (range 3)) :when (> x 1) :when (> x 2) (y (range 3))

quoll03:03:13

No, that is invalid syntax. But you can say:

(for [x (range 3) :when (> x 1) :when (> x 2) y (range 3)] ...)
Of course, this is an empty sequence, but if the first range moves up to 4, then it works:
(for [x (range 4) :when (> x 1) :when (> x 2) y (range 3)] [x y])

([3 0] [3 1] [3 2])

hiredman02:03:48

This readme is, I dunno, it is important to swing for the fences I guess

Jon Olick02:03:09

basically double when?

Jon Olick02:03:18

or combining when while etc

hiredman02:03:25

Each when is like wrapping in a call to filter

Jon Olick02:03:35

so its arbitrary

hiredman02:03:45

While is like wrapping in a call to take-while

hiredman02:03:55

I dunno what you mean by arbitrary

Jon Olick02:03:10

as many as you want of whatever you want and in any order

Jon Olick02:03:44

:let :when :let :when :while

Jon Olick02:03:50

not that anybody should actually do that

Jon Olick02:03:55

but if the language supports it…

hiredman02:03:22

For doesn't allow :when, :let, or :while before the fist sequence binding

Jon Olick02:03:34

thats good to know

hiredman02:03:16

I thinking writing your own lisp is a great project, and looking at clojure for inspiration while doing it is great, but saying it is clojure when you don't know clojure might not be a the best plan

Jon Olick02:03:57

I’m an experienced coder of many languages, this is my first interaction with clojure of course

Jon Olick02:03:26

I’m trying to be careful, but yes, great testing is required

craftybones02:03:37

I found that I made a lot more progress after I stopped trying to find analogous constructs from other languages

hiredman02:03:55

If you are going to claim to be faster then clojure on the jvm, then I think you need to be clear about what your benchmarks are. And I would be shocked if you are new to clojure if you are benchmark it well. But even what "well" means can be debated(start up performance, before jit after jit, jit agnostic, etc)

Jon Olick02:03:57

of course, I’m not claiming (yet) thats its faster in every case

Jon Olick02:03:08

it is faster though in some cases

Jon Olick02:03:38

though the implementation is incomplete, so who knows if that will still be a 2x perf gain vs JVM when I’m done

Jon Olick02:03:10

to be clear, I never expected it to be faster than JVM, but it turns out it is

Jon Olick02:03:35

I just wanted it to be comparable in simple cases

Jon Olick02:03:47

as I got to optimizing though, its much faster in some cases

Jon Olick02:03:20

but don’t take my word for it, and don’t measure it until its more complete 🙂

Jon Olick02:03:36

when it gets further along I’ll benchmark it more properly

hiredman02:03:07

Like, as a beginner, maybe you are just typing stuff in the repl, benchmarking the special cases interpreter clojure uses for simple forms in the repl, when most complex clojure programs are compiled to jvm bytecode and then fed to the jvm and then host loops are chewed through by the jit

Jon Olick02:03:28

right, which is why I was surprised that it was faster

Jon Olick02:03:30

it shouldn’t be

Jon Olick02:03:38

unless JVM is just optimizing poorly the code

hiredman02:03:14

Like I said, depending on what you are testing, you may just be testing in a way that is slow

hiredman02:03:41

And being a beginner you don't know that, and don't give any details of your benchmarking in the readme

Jon Olick02:03:50

really I just want an embeddable clojure

quoll02:03:06

Embeddable... as in, on embedded hardware, or embedded in another system?

Jon Olick02:03:15

meaning, embeddable inside another program written in some other language with minimal overhead and fuss and compiling nonsense

quoll02:03:45

If it's in a JVM language, then there are APIs for this. If it's on a Javascript (or Javascript compatible) system, then that's supported too. If it's in a binary system, and you don't want to start a VM, then there are better languages, such as https://ferret-lang.org/ (which was built to be a native Clojure)

Jon Olick02:03:53

thats the real goal

Jon Olick02:03:02

and fast enough to be able to do real things

Jon Olick02:03:18

we will see where it ends up

Jon Olick02:03:23

its very early days for it

hiredman02:03:47

Sure, but I suspect you would be happier with something like sbcl

Jon Olick02:03:11

This is a single file library 🙂

Jon Olick02:03:31

its the simplest embeddable method

hiredman02:03:00

That is unlikely to be clojure

Jon Olick02:03:27

watch me 😉

Jon Olick02:03:54

if I fail, then I’ll fail in blazing glory

Jon Olick02:03:12

also, I really don’t like the JVM

Jon Olick02:03:15

or Java in general

hiredman02:03:20

I mean, I've been hanging out in various clojure channels since the early days, I've watched lots

Jon Olick02:03:28

which is why I’m like “hells no” to that

Jon Olick02:03:35

and no, graaal VM or none of that

hiredman02:03:37

Yeah, which is why I suggested you look at sbcl

Jon Olick02:03:41

you don’t need to do anything nearly as complicated

Jon Olick02:03:51

people are over engineering it imo

hiredman02:03:52

Steel bear common lisp

hiredman02:03:10

Or ecl (embeddable common lisp)

craftybones02:03:46

@zelexi - quick question. You’ve about 3000 lines of code, but I don’t see any tests. How do you detect/handle any regression? It looks like you’ve implemented persistent vectors and bi directional persistent vectors too. How do you verify expected behaviour?

Jon Olick02:03:29

Thats on the TODO, and if there is a good set of test programs to run which do that, please point it out

hiredman02:03:44

Clojure was designed to run hosted on some platform, as the rationale mentions

craftybones02:03:09

I mean, as of now, you’ve benchmarked, but how are you so sure that what you are benchmarking works to begin with?

Jon Olick02:03:10

I just started this like a couple weeks ago or so

Jon Olick02:03:16

so its all baby infancy right now

Jon Olick02:03:22

I’m just trying to get my footing in the right place

Jon Olick02:03:40

test.clj tests for correctness

Jon Olick02:03:48

test2, test3 also test other stuff

Jon Olick02:03:52

not every test was saved

Jon Olick02:03:00

but its not well organized at the moment

Jon Olick02:03:13

I also use it at work for real things

Jon Olick02:03:18

so it does get some actual usage

craftybones02:03:22

There are no tests at all for any of the vectors stuff

Jon Olick02:03:31

thats cause vectors aren’t implemented yet

Jon Olick02:03:37

at least, not at the clojure level

Jon Olick02:03:45

I have written up the C++ code to do it

Jon Olick02:03:51

and MAPS use vectors as the underlying type

craftybones02:03:39

Why not test the C++ code itself? I mean, testing your interpreter for correctness is one thing, but there’s so much code out there, that it might make sense to write at least a few unit tests maybe? At least that’s how I feel like I have a grip on things

Jon Olick02:03:46

I have tests for that

Jon Olick02:03:54

but its commented out

Jon Olick02:03:05

not run unless I want to test

Jon Olick02:03:00

I don’t think its ready for real-world tests yet

Jon Olick02:03:04

its just not complete yet

craftybones02:03:04

why not stick a target in your Makefile and make it repeatable instead of commenting out some where?

Jon Olick02:03:24

somebody else wrote the makefile

Jon Olick02:03:38

was just a day ago or so

Jon Olick02:03:42

but anyways 🙂

quoll02:03:46

Oh, I missed the link to jo_lisp. Nice. I mentioned in a thread that this sort of thing https://ferret-lang.org/#outline-container-sec-2, but I'm almost thinking I shouldn't say so, since I think that it's always worthwhile trying these things again. After all, it's always a valuable learning exercise, and anyone can potentially come up with ideas that other people haven't had before!

Jon Olick02:03:47

yes, there’s lots to do

Jon Olick02:03:08

it has been invaluable to me in learning the language

👍 1
Jon Olick02:03:15

I have to explore every nook and cranny

craftybones02:03:49

That’s good to hear. I would just hold off on benchmarking or saying anything public yet. The clojure community is generally quite welcoming, but you’d definitely ruffle a few feathers if you make bold claims and your Makefile is 3 days old

Jon Olick02:03:12

lol 🙂 not claiming anything other than goals at the moment

Jon Olick03:03:30

ferret-lang is cool!

Jon Olick03:03:27

great unit tests in the docs there too

ahungry03:03:35

https://janet-lang.org/ is by the author, and more clojure-like (and probably the most embeddable clojure-like atm - great C interop) - edit: correction - fennel === janet author - ferret is not - should have double checked before commenting (ferret seems to keep parity with clojure while janet/fennel diverge)

ahungry03:03:48

If you need to be in C/C++, having these options are amazing - problem with any of the C-buddy langs as an option for general computing is that it's very hard to compete with the ecosystems/momentum of the higher level languages (even if they may be less performant) - I like using janet or bb for various things since they both have fast startup, but languages are never really competing in a 1 on 1 void of lang vs lang - its always lang+ecosystem vs lang+ecosystem, and its difficult for any ecosystem to beat out npm or maven (and stack clojars/gitlibs on top)

Jon Olick03:03:11

That's fine, I'm making it for me mostly

Jon Olick03:03:41

And anybody else who wants it, but even if it's only me that finds it useful, that's good enough for me

ahungry03:03:40

I think that's awesome - I just caught the tail end of the conversation and the mention of ferret-lang - are you transpiling into generated c/c++, or making a VM/bytecode layer?

Jon Olick03:03:40

bytecode layer

Jon Olick03:03:13

right now I’m just trying to get the language down 100%

Jon Olick03:03:20

and tbh its great

Jon Olick03:03:24

clojure is winning me over

Jon Olick03:03:55

I want basically instant startup time

Jon Olick03:03:05

and no compiles

Jon Olick03:03:17

so it can be used in place of scripts

Jon Olick03:03:30

like replacing perl or bash etc

quoll14:03:01

This is exactly the use case of babashka. (Hence the "bash" in the middle of the name).

quoll14:03:55

It's a binary (yes, built with the graalvm compiler, but you don't have to do that. You can just download the binary), it starts instantly, and it does Clojure

quoll14:03:34

For a long-running process, then Clojure/JVM is better, but the JVM can compete with C++ in that environment too.

emccue03:03:41

if you want a reference for a parser, i wrote an edn parser in rust recently

emccue03:03:39

its basically just one chonky file. i don't think its impossible to translate to C if that is your chosen life path. stuff like uuids and bigints would be a thing to keep in mind

Jon Olick03:03:04

yeah, I started implementing bigints and bigfloats

Jon Olick03:03:17

seems massively inefficient use of compute tbh

Jon Olick03:03:23

64-bit is not enough for people?

emccue03:03:33

Also > its the simplest embeddable method If its a C/C++ codebase yes. If its anything else then the implicit "we don't have anything resembling a package manager" state of the world is no longer true

Jon Olick03:03:30

I work with Sean Barret (author of stb libraries) we do single file libs all the time

Jon Olick03:03:38

It's great for just plop in and go

Jon Olick03:03:03

Again though, I'm talking about C/C++

Ben Sless03:03:20

Why hate the JVM though? It's a neat runtime, in spite of its flaws.

Jon Olick03:03:27

I don't want to ruffle any religion feathers too much, sufficed to say, I don't like the JVM or java at all. It's kind of repulsive to me. I like clojure though

Ben Sless03:03:12

Don't worry, non of us work for Oracle. I get not liking java but the JVM is just a stack machine with GC and great JIT. What's wrong with that? :thinking_face:

Jon Olick03:03:16

Yeah saying any more will just spark a debate and I don't want to debate right now lol

Jon Olick03:03:52

I know a whole industry is built around java, but it's just not my cup of tea

aratare09:03:44

Out of curiosity, why C/C++ instead of Rust or Go if you're looking for performance?

seancorfield03:03:54

Hey folks, try to remember to use threads for conversations please -- especially long, rambling ones that are unlikely to be of interest to most of the nearly 15K members of this channel. Thank you. /admin

👍 10
❤️ 5
parens 4
🧵 2
💯 1
quan xing08:03:23

In next.jdbc. I want to get camlCase key in result map

(require '[next.jdbc.optional :as jdbc-opt])
  (defn as-caml-maps
    [rs opts]
    (jdbc-opt/as-maps rs (assoc opts :label-fn csk/->camelCase)))
  (query ds ["select * from wf_run_task limit 1"] {:builder-fn as-caml-maps})
result : [{ :user_name "Jerry"}] is not :userName

dharrigan09:03:21

A bit long, but here you go:

dharrigan09:03:22

(next.jdbc/execute! db ["select * from starship"] {:builder-fn (fn [rs opts] (next.jdbc.result-set/as-modified-maps rs (assoc opts :qualifier-fn camel-snake-kebab.core/->camelCase :label-fn camel-snake-kebab.core/->camelCase)))})

dharrigan09:03:52

And I end up with this:

dharrigan10:03:10

;; [#:starship{:class "Constitution",
;;             :uuid #uuid "ba91976e-a01f-4165-957a-f5d5d50ea7a3",
;;             :image "ncc1701-a.jpg",
;;             :created #inst "2021-05-02T19:19:25.915454000-00:00",
;;             :captain "James T. Kirk",
;;             :affiliation "United Federation of Planets",
;;             :registry "NCC-1701-A",
;;             :starshipId 3,
;;             :launched 2286}

dharrigan10:03:17

notice startshipId is camelcase

popeye09:03:12

I am practising clojure ring and I am hitting a post req and getting the value in the body as rg.eclipse.jetty.server.HttpInputOverHTTP how to retrieve the value from body? I refereed https://stackoverflow.com/questions/42829594/how-to-get-the-content-of-httpinputoverhttp-in-clojure-compojure-ring-project and added (wrap-multipart-params) handler, my body parameter from input is :body {:Studyid 45}

oly11:03:29

struggling to google this how do i do "\" if i eval that in a repl it fails which I get so I though i would do "\\" but that prints 2 slashes I get the meaning of the slash just not how to make it a single slash, hitting an issue where I have \= in a string causing me issues.

leifericf11:03:58

Do you mean like this?

oly11:03:48

yeah I am not using print though this is a string I have when I eval it shows 2 and it fails when i pass it to another function I assume because its also seeing 2 slashes

oly11:03:41

I guess that then becomes a question why does eval show differently to print

leifericf11:03:36

Oh, yeah! How peculiar. When I evaluate just \ or "\" the REPL hangs indefinitely. Interesting. I don’t know why that happens.

oly11:03:52

(str "" \u005C "=")

oly11:03:05

even trying that eval gives me \\= 😛

1
oly11:03:24

perhaps its just a read hearing and i actually have another issue

leifericf11:03:02

Did you mean red herring? ☺️

leifericf11:03:53

Now I’m also curious what’s going on here 😅

oly11:03:22

yeah, I did my string was indeed wrong and the slash is actually fine when passed in, but its still a bit weird you would expect it to show the real version when you eval

leifericf11:03:36

Interesting…

user=> \u005C
\\
user=> (str \u005C)
"\\"
005C is the Unicode for \.

leifericf12:03:03

I found this: https://stackoverflow.com/a/48662861/195964

user=> "ex\\*mple"
"ex\\*mple"
user=> (println "ex\\*mple")
ex\*mple
nil

oly12:03:30

I think i came across that and glossed over it because it was doing a replace

leifericf12:03:44

I think what’s happening is that, when you evaluate \, you evaluate the escape character by itself (Clojure uses Java strings, which use \ as its escape character). To print \, it must be escaped, so \\ is the correct way to represent a single \.

user=> (str "\\")
"\\"
user=> (count "\\")
1
user=> (count (str "\\"))
1
user=> (println (str "\\"))
\
nil
user=> (println "\\")
\
nil
user=> (println (str \u005C "="))
\=
nil
It prints as one \, and the count is 1.

leifericf12:03:12

My current understanding is that when we evaluate expressions like "\\" and (str "\\"), we see the escaped string meant for machine consumption in the REPL. But when we pass the same string to certain functions like println, we see the unescaped string meant for human consumption in the REPL. The actual string is the same in both cases, but its representation is different. Perhaps a more experienced Clojurian could confirm or disconfirm and provide further clarification.

oly12:03:36

yeah certainly seems that way, one of those quirks that can catch you out when your not expecting it 🙂

👍 1
leifericf12:03:28

Yeah! Thanks for asking this question. Although it derailed my task at work, I learned something new by digging into it ☺️

Sakib12:03:38

I was thinking about posting a question. Then find the answer by myself 😺. How and in which channel should I discuss such thing where I sort of have an answer?

leifericf12:03:27

If you think it might be interesting or useful to other beginners, then I suppose this channels is a good place for it!

🙂 1
👍 1
Gunnar12:03:25

Just post the question and then answer yourself in a thread

👍 1
Jimmy Alejandro Alvarez Calderon13:03:07

Hey guys, how is it going?. Currently I'm reading an edn file as an exercise of my clojure training. Im using the following function which seems to find the file but not able to read and serialize the edn content

(defn read-edn-file
   "read edn file content"
  [file-path]
  (clojure.edn/read (java.io.PushbackReader. ( file-path))))
The error I got is No reader function for tag [var] . As my research looks like there is a reader definition missing but actually I don't know what reader should i go with and how to define it. Any suggestion will be appreciated

flowthing16:03:48

Your EDN file has a tagged element (https://github.com/edn-format/edn#tagged-elements) that the Clojure EDN reader doesn't know how to read by default. It's difficult to say what that element is from that error message alone.

flowthing16:03:21

You can use the :readers option to pass a map from symbol to function that knows how to read the tagged element.

flowthing16:03:59

For example:

⁣(slurp "/tmp/bar.edn")
;;=> "{:foo #var [:a]}\n"
(clojure.edn/read 
  {:readers {'var (fn [x] x)}}
  (java.io.PushbackReader. ( "/tmp/bar.edn")))
;;=> {:foo [:a]}

flowthing16:03:28

Alternatively, as a first step in debugging the issue, you can use :default:

(clojure.edn/read 
  {:default tagged-literal}
  (java.io.PushbackReader. ( "/tmp/bar.edn")))
;;=> {:foo #var [:a]}

Jimmy Alejandro Alvarez Calderon14:03:42

Using {:default tagged-literal} works for me

Jimmy Alejandro Alvarez Calderon14:03:38

I have a question over this function {:readers {'var (fn [x] x)}} . How do I figure out what function will be the (fn [x] x) for each tag-literal?

flowthing14:03:35

It can be what you need it to be. 🙂 That's the whole point.

flowthing14:03:45

The function defines how to read the tagged literal.

flowthing14:03:05

So for example, in your EDN file, you could have something like this:

{:date #my/date "2022-03-31"}
Then, you could have:
{:readers {'my/date (fn [date-string] (java.time.LocalDate/parse date-string))}}

flowthing14:03:34

Then, when you read the EDN, every value tagged with #my/date is going to be read into a LocalDate instance.

Jimmy Alejandro Alvarez Calderon20:03:21

Uff, that looks good!!!. thanks bro. i will refactor the script to use specific readers

flowthing09:04:20

Happy to help.

dumrat14:03:07

What does this represent? (repl output) #{[#:dumrat.bookkeeper{:ledger 2}]}

ghadi14:03:44

a set, containing a single element, a vector, which contains a single element, a map

dumrat14:03:24

What does #: stand for?

ghadi14:03:25

the map is written in the "namespaced" syntax #:dumrat.bookkeeper{:ledger 2} which is equivalent to {:dumrat.bookkeeper/ledger 2}

ghadi14:03:14

you can disable the namespaced syntax with: (set! *print-namespace-maps* false)

👍 3
dumrat14:03:37

oh. dumb me

mister_m15:03:51

Is there a more up to date version of https://cognitect.com/blog/2013/06/04/clojure-workflow-reloaded available? I've been sort of doing this with my own component system to just mess around with the system in the repl (without the reloading of various namespaces). Has anything majorly changed since this was written?

Alex Miller (Clojure team)15:03:51

not to my knowledge, although I'd suggest ideas from https://clojure.org/guides/dev_startup_time can help a lot with startup time

mister_m15:03:30

thanks Alex

popeye16:03:44

I am passing a hash-map from a one end-point to another using compojure as {:study-id 1 name "john"} but when I recieve it another end point it is converting hash-map to the string type, How can we overcome this problem?

Ferdinand Beyer16:03:17

Can you share some code please? I guess you mean you call one handler function from another? Maybe updating the request parameter? How exactly?

quan xing18:03:37

How can I understand #' ? I saw it from https://clojure.org/guides/weird_characters#_var_quote and I known #' is var. but in realword project's code I can't understand it. like this:

(->> params
          (#'profile/create-profile conn)
Why use #' or not use like as:
(->> params
          (profile/create-profile conn)
(defn foo[x y]
  (+ x y))
(foo 1 2) =>3
(#'foo 1 2) =>3
Why use the #'

mruzekw18:03:37

#'profile/create-profile is referring to the reference itself, here that's the symbol profile/create-profile Although you can invoke a function with the #' , that's only really used to add to read metadata to it from it.

mruzekw18:03:37

profile/create-profile = I'm referencing the value this symbol points to. #'profile/create-profile = I'm referencing the symbol itself.

mruzekw19:03:02

https://replit.com/@mruzekw/ClojureVarExample#main.clj Look at this http://repl.it, first run will be slow because it's pulling down all the deps

dgb2319:03:47

Both the var and the fn value implement function behavior. But the var quote can help you with rebinding with the REPL: https://clojure.org/guides/repl/enhancing_your_repl_workflow#writing-repl-friendly-programs

mruzekw19:03:51

Huh. Didn't know about IFn for both. Thanks for that context

👍 1
quan xing00:03:14

Thanks, for reply. I know #'profile/create-profile = I'm referencing the symbol itself. I don't understand Both are function calls, Why is use '# or not direct call function use name.

(defn create-profile*
  ([i] (create-profile* *pool* i {}))
  ([i params] (create-profile* *pool* i params))
  ([conn i params]
   (let [params (merge {:id (mk-uuid "profile" i)
                        :fullname (str "Profile " i)
                        :email (str "profile" i "[email protected]")
                        :password "123123"
                        :is-demo false}
                       params)]
     (->> params
          (#'profile/create-profile conn)
          (#'profile/create-profile-relations conn)))))
why not direct call function like this:
(->> params
          (profile/create-profile conn)
          (profile/create-profile-relations conn))
I don't see the difference, so I'm confused

Ferdinand Beyer06:03:04

Not sure about your specific example, but there are two tricks to use #'fn-var instead of fn-var directly: • Accessing private vars. If your namespace defines a function using (defn-, it will be private, and not callable from other namespaces. Accessing the var with #' will still be possible though. This is often used in tests, to test private functions from a separate test namespace. Maybe profile/create-profile is private in your case? • Keeping indirection. When resolving a symbol to a function, to pass this function to another function, updating the original var will not cause this already resolved “old version” to be updated. For example, Ring server adapters take a handler function: (start-server handler). When you now change and evaluate your handler in the REPL without restarting the server, the server will keep calling the old handler. Using (start-server #'handler) passes the var as a handler, and every time this var is called it will resolve to the latest version. So changing the defn of handler will immediately be reflected without restarting the server.

noisesmith23:03:32

rephrasing something more succinctly: when using a var, the current value is looked up before every call, when calling the function, the lookup happens only once if the function was an argument passed in

(cmd)user=> (defn foo [f] #(vector (f) (f)))
#'user/foo
(cmd)user=> (defn bar [] 12)
#'user/bar
(cmd)user=> (def captured-f (foo bar))
#'user/captured-f
(cmd)user=> (def indirected-f (foo #'bar))
#'user/indirected-f
(ins)user=> (captured-f)
[12 12]
(ins)user=> (indirected-f)
[12 12]
(ins)user=> (defn bar [] 42)
#'user/bar
(cmd)user=> (captured-f)
[12 12]
(cmd)user=> (indirected-f)
[42 42]

quan xing01:04:21

• thank you @U031CHTGX1T The words you explain are simple and easy to understand • and @U051SS2EU thank you as same. Your code should have a deeper understanding of the above text

👍 1
Michael Anckaert20:03:34

I have a question regarding protocols and extend-protocol . Is there any reason to favour extend-protocol over modifying your code that uses defrecord? I can see that when you want to update a running Clojure instance that extend-protocol is useful. But when updating an application I would immediately favour updating the initial call to defrecord to implemented the protocol.

Alex Miller (Clojure team)20:03:02

putting it in on defrecord is the fastest possible implementation

Alex Miller (Clojure team)20:03:32

you are using exactly what Java leverages on the JVM to make virtual calls fast

Alex Miller (Clojure team)20:03:01

but you could also say you have tightly coupled the type to the behavior

👍 1
dgb2320:03:38

Can you extend protocol on things you don’t own?

Michael Anckaert20:03:09

From what I read yes, you can! I just saw an example where you can extend a protocol on a boolean:

"(extend-protocol Marketable
 	  String
 	    (make-slogan [s] (str ​\"​ s ​\"​ ​" is a string! WOW!"​))
 	  Boolean
 	    (make-slogan [b] (str b  ​" is one of the two surviving Booleans!"​)))"

🆒 1
Alex Miller (Clojure team)20:03:09

yes, although there is some guidance about that

dgb2320:03:26

These make a lot of sense

dgb2320:03:42

See here for an example in the JS world where monkey patching led to problems (under 2.3): https://2ality.com/2022/03/naming-conflicts.html

phronmophobic20:03:33

Are there any resources or guidance about how to decide if a protocol should set :extend-via-metadata to true? Should authors default to allowing extension via metadata?

Alex Miller (Clojure team)20:03:46

if it's available for open extension, I think doing so opens some possibilities

Alex Miller (Clojure team)20:03:07

but worth considering that satisfies? does not catch metadata extensions

phronmophobic20:03:02

Does it affect performance?

Alex Miller (Clojure team)20:03:13

per https://clojure.org/reference/protocols#_extend_via_metadata - these are checked in the order of direct implementation (so no change there), then metadata, then external extension. But the checks happen regardless.

👍 1
Alex Miller (Clojure team)20:03:10

we made external extension slower to add the check when we added metadata extension but that was considered and assessed at that point

hiredman21:03:58

For protocols that do, uh, I guess business logic sort of things, I think it is a no brainner to allow for metadata extension

👍 1
phronmophobic21:03:24

awesome. that's just what I was hoping to learn. I think I have a few protocols that I think would benefit from being open to extension via metadata. Thanks! 🙏

Vishva Nath Dutt Sharma23:03:20

hey need some help in why compilation is throwing error CompilerException java.lang.RuntimeException: No such var: I just declared a constant name

leifericf06:03:05

Can you share the code which produced this error?

jacekschae06:03:08

If you are evaluating in the REPL you might need to reload the ns so that the declared var is available.

Vishva Nath Dutt Sharma15:04:37

hey thanks, I was able to figure out problem in my code.

dpsutton23:03:13

will need a bit more information than that

🧵 1