Fork me on GitHub
#beginners
<
2022-10-31
>
dumrat03:10:16

Just out of curiosity, Why does Rich Hickey not do any Clojure related talks anymore? I know he did a history of Clojure video in 2021 (I think). But apart from that, there's silence. I really enjoyed his presentations

Alex Miller (Clojure team)03:10:58

Because theyโ€™re really time consuming

๐Ÿ‘ 1
seancorfield04:10:39

As someone who used to do a lot of conference talks around the world for about a decade, I can totally support that! I think most people (who haven't given conference talks) have no idea just how much work goes into them -- and also how it can kind of "spoil" the conference for you, until you've given your talk (so an end-of-conference keynote is, in many ways, much worse than a regular talk during the conference).

seancorfield04:10:26

I stopped speaking at conferences in 2013 and I have really enjoyed attending conferences since then! ๐Ÿ™‚

seancorfield04:10:11

(although I keep promising myself I'll submit a talk to Conj one year!)

Lennart Buit06:10:18

Please do Sean! I, for one, would be interested :)

practicalli-johnny08:10:40

@UC1DTFY1G what talks would you want Rich Hickey to actually give? I still get value revisiting many of the videos Rich has done over the years and its not immediately obvious to me what new topics would be beneficial. As others have stated, preparing a talk can take many days or many weeks to prepare. The live broadcasts on Clojure I did for an hour each week for Practicalli would take the whole week to prepare and most would have benefited from more preparation. Personally, I would rather Rich focused on stewarding Clojure itself, especially as more and more of the Clojure community are sharing their experiences.

๐Ÿ‘ 1
dumrat08:10:27

@U05254DQM Nothing specific. Sends out a good message if the creator of the language makes a public appearance once in a while. That's all. Some people actually ARE sheep who'd rather follow someone ๐Ÿ˜„ (myself included sometime) For those who lack the skills to practically grok everything by themselves, it's a good heuristic to follow others who are respected. (This is true no matter how much I dislike this fact)

practicalli-johnny10:10:41

There are many people in Cognitect (now NuBank) who regularly give talks, as well as a hugely diverse community. I think its highly dubious for one person to be seen as the only respected source for a language and personally this would be one thing that deters me from that language. Clojure is an established language and used by those who appreciate its qualities and spend time investing in it. I think the software industry would be much more mature if everyone had the opportunity to meaningfully consider the language(s) they use.

1
๐Ÿ‘ 1
dumrat06:10:56

How useful do you find visualization tools like portal or reveal?

Ben Sless06:10:12

As useful as taps are, which is very

seancorfield06:10:19

For me, Portal is a core part of my workflow. I use VS Code/Calva with the Portal extension (so it runs inside VS Code) and I have my actual REPL hidden and rely entirely on Portal. The ability to use datafy/`nav` on complex data structures as well as multiple ways to visualize that data is immensely powerful.

seancorfield06:10:33

I really need to do some screencasts of how I work since it's a lot easier to show than to tell...

๐Ÿ‘ 4
seancorfield06:10:31

Even the most basic aspect: showing hash maps and vectors as tables is a huge comprehensibility boost over plain text in a REPL.

dumrat06:10:16

@U04V70XH6 One of the most difficult parts of learning Clojure for me has been getting the correct dev setup. I think the REPL workflow and integrating tools like these should be front and center. Instead I found out these stuff slowly. Anyway, please do a screencast. That'd really help me and I guess many others.

dumrat06:10:53

It doesn't help that I'm stuck on Windows either

dumrat06:10:05

Clojure seems unaware that Windows exists

dumrat07:10:08

@U04V70XH6 One question. I need to tap> something to send it to portal right? If I just Ctrl+Enter in calva, that form gets sent to repl and evaled. Is it possible to have this kind of setup with portal without explicitly adding tap>s all over the code?

seancorfield07:10:15

I do all my dev on Windows -- both at work and for my OSS projects (two separate machines). I use WSL2 for all the Clojure stuff and run VS Code on Windows.

dumrat07:10:39

@U04V70XH6 Yeah, I realized I need WSL2 way too late ๐Ÿ˜„

seancorfield07:10:48

My https://github.com/seancorfield/vscode-calva-setup repo has my VS Code / Calva / Joyride / Portal setup, for the most part, and my https://github.com/seancorfield/dot-clojure repo has my aliases and my dev.clj which starts my REPL (and patches clojure.tools.logging if Portal is on the classpath).

seancorfield07:10:28

I use the Portal middleware for nREPL so all my evals are tap>'d and sent to Portal, although I have some customization around that so evaluations that invoke tap> directly are handled differently. My Calva customREPLCommandSnippet settings are in my vscode repo in an EDN file and that's where all my tap>-related magic happens.

seancorfield07:10:34

I use Joyride to open VS Code's Simple Browser with http://clojuredocs.org or Java Docs as needed -- so I don't have to switch to a browser. I use Portal for all my REPL output -- and keep Calva's nREPL output window hidden (I never type into a REPL).

seancorfield07:10:13

(midnight here so bed time -- happy to discuss in depth tomorrow or another day)

๐Ÿ‘ 1
dumrat07:10:18

@U04V70XH6 ok, I will go through and try to make sense

dumrat07:10:44

Having to manually tap> is what keeps putting me off

dumrat07:10:00

Thanks, I will have a look and bother you in case I can't make it work I guess ๐Ÿ˜‚

skylize07:10:51

Is there a way to attach metadata to something in such a way that it shows up automatically in some variation of print? (Preferably with at least some resistance to losing that metadata during common transformations.) i.e. something like

(defn Foo [x] ... make x self-descriptive as a Foo ...)
(let [foo (Foo "foo")]
  (prn foo))
=> Foo <"foo">
=> nil

pithyless07:10:47

Do you mean via https://clojure.org/reference/metadata?

(with-meta {:foo :bar} {:kind :Foo})
=> {:foo :bar}

(meta (with-meta {:foo :bar} {:kind :Foo}))
=> {:kind :Foo}
You can always write a custom prn function that also prints out the meta. Otherwise it depends on your dev env - eg. Portal visually indicates that certain data has metadata attached to it.

pithyless07:10:35

Or do you mean more along the lines of creating a defrecord and overwriting the default print-methods?

(defrecord Foo [bar]
  Object
  (toString ^String [this] (my-custom-string this)))

(defmethod print-method Foo
  [this ^Writer w]
  (.write w (my-custom-string this)))

(.addMethod pprint/simple-dispatch Foo
  (fn [this] (print-method this *out*)))

skylize07:10:02

Not sure what I mean, as far as what the language actually offers. I just have some things that are kind of like types, and would like for the info that "this is a thing" to present itself on introspection, even though I'm not looking for any sort of type enforcement.

pithyless07:10:39

Sounds like you probably want to use https://clojure.org/reference/metadata. Check out e.g. "Applying Viewers" in https://github.clerk.garden/nextjournal/book-of-clerk/commit/70d0459fbe941e689e0c2e7df0afc887eaf5900b/#%F0%9F%A4%B9%F0%9F%8F%BB_applying_viewers to see how Clerk uses metadata notation to pass around and react on type information, without interfering with the original value.

pithyless07:10:04

And I just realized, Clojure even has built-in *print-meta* : https://clojure.org/reference/metadata#_print_meta

skylize13:10:34

Thank you. I was already aware of the existence of metadata. The problem (ignoring that it cannot augment simple values ...

(def foo ^:Foo "foo") ;; Syntax error
(def foo ^:Foo 123) ;; Syntax error
... ) is that it does not present itself organically in any way.
> (def foo ^:Foo ["foo"])
nil
> (prn foo)
["foo"]
nil
You have to go out of your way to ask for it.
> (prn (meta foo))
{:Foo true}
nil

skylize13:10:57

Or maybe I just need some trick to get Calva (or nrepl or clojure-lsp) to surface metadata?

pithyless13:10:54

Have you tried:

(set! *print-meta* true)

pithyless13:10:38

it changes the global state of your runtime, so it would be better to hook into the nrepl printer and just modify it via binding - but this should start printing metadata for all your repl interactions

skylize13:10:03

Interesting idea. I wonder how much noise that will add from other things.

skylize13:10:21

I don't think I realized you could set that globally.

pithyless13:10:50

it's a dynamic variable, which is why it uses the asterisk naming convention *_name_* - it's because theoretically, it can be modified at any time; Usually you don't want to modify it globally without scoping it via binding if you can help it :)

pithyless13:10:27

You can read more about dynamic vars here: https://clojure.org/reference/vars

pithyless13:10:55

But if setting the *print-meta* gives you the desired results, I would encourage you to dig further and see how Calva is printing the repl results, because hopefully you can just hook in and modify that behavior locally with binding vs changing it globally for your entire runtime. Perhaps ask on #CBE668G4R?

skylize19:11:20

Seems like the best answer is probably just to define types. The simplest example would be a record for what would otherwise be map data, since that comes with tagged map-like printing already built in.

(defrecord Foo [foo])
(->Foo "foo")
; => #my-ns.Foo{:foo "foo"}

Lior Neria08:10:07

Hi ๐Ÿ‘‹, I need to implement a function that iteratively goes through all the folders that are under resources and reads all the json files that are in each subfolder and unites them into one file - so that each subfolder will have one json file. I was able to implement the function in the meantime only with a reference to the specific path and to combine two Json files only. Is anyone knows how I can run iteratively on all the subfolders? Thank you :)

dumrat09:10:35

You need to go through all the files in the folder, and map json/read-value and merge everything later I guess:

(->> 
  (get-filenames)
  (map #(json/read-value (slurp %))
  ...merge)
See here on how to get all files in folder: https://stackoverflow.com/a/8566653/466694 If you need to output the merged json to a file, you can do that afterwards.

๐Ÿ‘ 1
Martin Pลฏda09:10:31

Untested:

(defn merge-jsons
  "file should be java.io.File, eg (File. string-path)"
  [file]
  (let [all-files (.listFiles file)
        subfolders (filter #(.isDirectory %) all-files)
        subfiles (filter #(.isFile %) all-files)]
    (->> subfiles
         (map #(json/read-value (slurp %)))
         (json/write-value-as-bytes))
    (doseq [f subfolders]
      (merge-jsons f))))
file-seq and .listFiles have different results (`file-seq` returns all files, .listFiles only these on the current "level").

๐Ÿ‘ 1
Martin Pลฏda09:10:22

And you have to spit somewhere the result of json/write-value-as-bytes.

dumrat09:10:56

How do I do nested desctructurings? Example:

(let [{:keys [tag content]}
      {:tag :seriesKey :content ["2372"]}]
  [tag content])
=> 
[:seriesKey ["2372"]]

;; Now if I wanted to "unroll" the :content, 

(let [{:keys [tag [content]]}
      {:tag :seriesKey :content ["2372"]}]
  [tag content])
=> 
{:keys [tag [content]]} - failed: simple-symbol? at:....
{:keys [tag [content]]} - failed: vector? at:....
Is there a way to do such "nested" destructuring?

delaguardo09:10:32

(let [{:keys [tag]
       [content] :content}
      {:tag :seriesKey :content ["2372"]}]
  [tag content])
try this

๐Ÿ‘ 1
dumrat09:10:52

@U04V4KLKC wow, great. Is that syntax for "naming" keys?

delaguardo09:10:07

I donโ€™t know if there is a name for this because this is the most basic destructuring primitive for maps ๐Ÿ™‚ Here is a complete guide for various destructuring options available in clojure. - https://gist.github.com/john2x/e1dca953548bfdfb9844

๐Ÿ‘ 1
oddsor09:10:50

You can check the official docs here for some examples too! https://clojure.org/guides/destructuring#_associative_destructuring

๐Ÿ‘ 1
Lukas09:10:53

Hello, when building an uberjar from my pedestal app, logging to file does not work anymore. โ€ข It works, when I start my project from the repl. โ€ข The pedestal samples work, differences to my project are โ—ฆ I created my project with deps-new and use the given tool chain Is there something obvious I'm missing? Did anyone run into the same issue?

Lukas13:10:32

adding the path of the logback config file as jvm argument, solves the problem java -Dlogback.configurationFile=file:path -jar ...

Benjamin09:10:31

jo is there a function with the semantic (first (filter pred coll)) some returns the return value of pred, but I want to "find" the first element for which pred is true

delaguardo09:10:11

https://clojure.atlassian.net/browse/CLJ-2056 there are some idioms you might copy to ypur project but non of them got landed in clojure core yet

Benjamin10:10:43

cool thanks

Jing Guo09:10:29

Iโ€™m really new to front-end development, but am thinking about developing a web app recently. People seem to suggest regent, which is based on React. Is this the โ€œsimplestโ€ approach for someone new but wants a nice UI? Or I miss somethingโ€ฆ

Benjamin10:10:44

Reagent is probably a good place to start. You can use #C034FQN490E to develop instantly. Example website: https://benjamin-asdf.github.io/scittle-prints-itself/

Jing Guo10:10:26

@U02CV2P4J6S thank you. Will check it out. I donโ€™t want to use any frameworks so Iโ€™m trying to figure out these things myself.

Benjamin10:10:10

https://www.youtube.com/watch?v=QEEPXuR5wLk this is a great walkthrough using only vanilla cljs (js interop) irrc

โค๏ธ 1
respatialized17:10:12

Depending on how text-heavy your pages are โ€“ if for example, you're building mostly static HTML with some interactivity tacked on that needs to talk to a backend โ€“ then you might want to give HTMX/ctmx some consideration. My understanding is that they offer interactivity without the overhead of JS and react, instead delegating the computation for interactivity to the backend. May not be appropriate if you want to create highly interactive front end content that doesn't require a backend component. https://htmx.org/ https://github.com/whamtet/ctmx

respatialized17:10:38

"Nice UI" in this context would be achieved using CSS rather than react; something like TailwindCSS could help you get something nice and customizable quickly. But it's very much a framework, so you may prefer to just use your own CSS instead. https://tailwindcss.com/

practicalli-johnny17:10:29

Reagent is pretty simple, essentially you write hiccup or selmer & html templates for the content and reagent manages the virtual DOM (updates the page efficiently) I use Bulma CSS library to add some nice styling. You can use a Clojure atom to manage state changes and if the component used data from the state, reagent manages the updates when that data changes. A very simple example: https://practical.li/clojurescript/web-design-basics/clojurebridge-london-website/ This is the development workflow I take https://practical.li/blog/posts/clojurescript-workflow-with-clojure-cli-tools-and-figwheel-main/

Jing Guo11:11:50

Thank you, @U05254DQM I found your website really useful.

Jing Guo11:11:51

@UFTRLDZEW thank you for your advice. I donโ€™t want to use Clojure framework, but I think CSS frameworks should be fine, if they do not introduce too much overheads. I think JS or Clojurescript seems to be โ€œslowโ€ whereas CSS seems to be fast? My personal website is static only, so not sure about the other side. EDIT: can I use garden library with tailwind?

Abhi Saxena15:10:09

Hi All, I just realized a strange behavior in Java API, where it rounds off the date as "2023-02-30" (Feb 30) to "2023-02-28T00:00:00Z"

(defn str-to-date [date-str]
  (LocalDate/parse date-str
                   (.toFormatter
                     (doto (DateTimeFormatterBuilder.) (.parseStrict)
                       (.appendOptional (DateTimeFormatter/ofPattern date-format-dd-MMM-yyyy))
                       (.appendOptional (DateTimeFormatter/ofPattern date-format-yyyy-MM-dd))))))
Is there a way to enforce Lenient and let it fail if this sort of input is provided.

Abhi Saxena17:10:47

Sure, let me try that out

dumrat17:10:32

I use clojure.xml to parse xml (data from many services): (xml/parse (.ByteArrayInputStream. (getBytes xmlstr))) I hit a snag with one xml though:

;Error printing return value (MalformedByteSequenceException) at com.sun.org.apache.xerces.internal.impl.io.UTF8Reader/invalidByte (UTF8Reader.java:702).
;Invalid byte 2 of 3-byte UTF-8 sequence.
What can I do here? Probably there's something wrong with the data but I don't control it. Is there a way to somehow ignore this singular error and continue as if nothing happened? ๐Ÿ˜„ Or to sanitize data?

dumrat18:10:58

NVM, (xml/parse (.ByteArrayInputStream. (getBytes xmlstr "UTF-8"))) works ๐Ÿ˜„

Ben Lieberman18:10:48

If I have a lazy seq of fn's, say as a result of repeatedly, what's the best way to apply those fn's to values? I've tried variations of using map and apply with no luck

Paul18:10:14

Sounds like you want reduce

andy.fingerhut18:10:32

There are at least some ways that map and apply could be used to apply functions in a sequence to values. For example:

user=> (def fn-lst [inc dec #(+ 3 %)])
#'user/fn-lst
user=> (map (fn [f] (f 2)) fn-lst)
(3 1 5)

andy.fingerhut18:10:13

And continuing that example for a variation:

user=> (map (fn [f v] (f v)) fn-lst [10 20 30])
(11 19 33)

Ben Lieberman18:10:13

This is a trivial example while I try to figure this but

(map (fn [x] (x 7)) (repeatedly rand-int))
this throws an ArityException

dumrat18:10:00

rand-int needs an arg

andy.fingerhut18:10:41

Here is something that might be what you are looking for?

user=> (map (fn [x] (x 7)) (take 20 (repeat rand-int)))
(2 5 4 0 6 6 1 4 2 0 6 1 1 2 0 4 1 1 6 4)

๐Ÿ‘ 1
andy.fingerhut18:10:52

Note repeat instead of repeatedly, which do very different things

dumrat18:10:28

@U0CMVHBL2 Is it better to "lift" the (take 20 to outside?

Ben Lieberman18:10:31

I am curious why repeatedly does not work here?

Ben Lieberman18:10:00

I use repeat all the time but to make seqs of things that are not functions

dumrat18:10:52

Takes a function of no args, presumably with side effects, and
returns an infinite (or length n if supplied) lazy sequence of calls
to it

andy.fingerhut18:10:54

I think it depends what you want -- my only purpose was to make a small example with small output ๐Ÿ™‚

๐Ÿ‘ 1
Ben Lieberman18:10:24

So does this

(take 5 (repeatedly #(rand-int 11)))
meet the "no args" criterion bc rand-int is inside an anonymous function?

Ben Lieberman18:10:58

(That's from clojuredocs)

andy.fingerhut18:10:27

In that example, rand-int is called with exactly 1 argument, the integer 11

andy.fingerhut18:10:42

#(rand-int 11) is an anonymous function that takes no arguments.

Ben Lieberman18:10:19

That's good to know, I did not know you could use anonymous functions like that