Fork me on GitHub
#clojure
<
2022-05-28
>
Jacob Rosenzweig00:05:50

Is there a common naming convention for patterns? Something like the convention of using a ? for boolean fns (e.g. string?)

seancorfield00:05:13

Do you mean for symbols bound to regular expression patterns?

Jacob Rosenzweig00:05:34

Yeah for the bindings themselves. E.g. (def alphanumeric-pattern #"[A-Za-z\d]")

dpsutton01:05:32

i think we usually prefix with re-. re-alphanumeric etc

👍 1
Jacob Rosenzweig01:05:28

I like that. Simple and clear

seancorfield01:05:12

Looking at our codebase, it seems we mostly use a -regex suffix.

Andy Wootton12:05:09

I like that better. I read -re as "in relation to".

emilaasa08:05:08

#naming-things is a channel I just started for discussions like these - one of my favorite kinds of channels from other programming language chats.

1
👍 1
chrisbroome04:05:10

anyone have an example of how to copy the contents of a ZipEntry to a string? i cannot figure this out for the life of me - the java docs are quite confusing for input/output streams

chrisbroome05:05:33

i figured it out... you have to navigate to the appropriate entry and then read from the underlying ZipInputStream - not the ZipEntry itself. :man-shrugging:

Carlo11:05:28

I'd like to understand better the mechanism behind clojure.repl/source. Here's a snippet:

(ns my-ns
  (:require [clojure.repl :as repl]))

(defn foo [a] (inc a))

(repl/source omicron.core/foo)
This prints
Source not found
I'd like to understand why this happens (isn't my file on the classpath too?) and what's the standard solution to get the source of the functions in your own project.

Carlo11:05:00

And by the way, why doesn't clojure put the source code in the metadata for the function? There has to be a tradeoff there, but I'm unsure where!

borkdude13:05:45

The namespace my-ns does not match omicron/core

borkdude13:05:26

The source function finds the .clj(c) file on the classpath, then reads until the line that is in the metadata and reads the entire form

Carlo14:05:08

@U04V15CAJ I made a mistake in copying; but this doesn't work either:

(ns omicron.core
  (:require [clojure.repl :as repl]))

(defn foo [a] (inc a))

(repl/source omicron.core/foo)

borkdude14:05:23

Where does your omicron.core source file live?

borkdude14:05:32

in src/omicron/core.clj on disk?

Carlo14:05:17

yes, but maybe it could be because I don't have the paths set up in my deps.edn?

borkdude14:05:47

src is automatically on the classpath, but perhaps if you restart your REPL it will work

Carlo14:05:03

unfortunately it doesn't even restarting. I can make a repro example, but it's just the snipped I pasted. I'm using:

;; CIDER 1.3.0 (Ukraine), nREPL 0.9.0
;; Clojure 1.11.0, Java 11.0.12

borkdude14:05:17

you don't need CIDER to test this. could you just go into a terminal with clj and then (require '[omicron.core]) and then (clojure.repl/source omicron.core/foo)?

Carlo14:05:59

Interestingly, clj errors out when I try the require:

user=> (require '[omicron.core])
Execution error (FileNotFoundException) at user/eval2 (REPL:1).
Could not locate omicron/core__init.class, omicron/core.clj or omicron/core.cljc on classpath.

Carlo14:05:54

But the file is definitely called src/omicron/core.clj and I'm invoking clj from the root of the project

borkdude14:05:05

Could you do a find . in the root?

borkdude14:05:13

or find src

Carlo14:05:21

/home/carlo/code/clojure/omicron λ tree .           
.
├── deps.edn
└── src
    └── omicron
        ├── core.clj
        └── new.clj

borkdude14:05:41

What's in your deps.edn

Carlo14:05:32

for now just {:paths [src]}

borkdude14:05:14

can you change that to ["src"]? :)

borkdude14:05:19

If you use clj-kondo, you would get a warning about this:

Carlo14:05:23

That was dumb on my part, sorry; anyway, now the code works in clj but still not in cider

borkdude14:05:27

The clj-kondo warning here is weird too btw, it should just be a string

borkdude14:05:32

you should restart cider

Carlo14:05:51

I restarted the repl, is that not enough?

borkdude14:05:22

the classpath is not updated dynamically, so you have to start a new CIDER REPL. if it doesn't work, perhaps you didn't restart it hard enough ;)

Carlo14:05:57

Let me restart it hard enough 😄

Carlo14:05:04

No, I rebooted everything and I still get Source not found in cider.

borkdude14:05:44

What does (System/getProperty "java.class.path") say? It should list src as one of the first things

Carlo14:05:45

it does mention src as the first path, yes

borkdude14:05:17

So what exactly does not work in CIDER, source doesn't print anything?

Carlo14:05:14

when I eval

(repl/source omicron.core/foo)
I get Source not found in the repl.

borkdude14:05:32

Maybe ask in #cider - don't know

Carlo14:05:58

thank you @U04V15CAJ! I appreciate the help in understanding it has to be a cider issue 🙂

👍 1
thiru16:05:19

Hey folks, wondering what you'd recommend to an experienced dev to get a deep understanding of clojure. Can be a book, blog series, video course, anything really

dorab17:05:03

I presume you mean a dev who is experienced in other programming languages but not Clojure. In that case, I'd recommend just writing your own Clojure code and reading the sources of libraries or Clojure itself. Depending on which other languages the experience is in, the biggest challenge is likely to be unlearning previous habits and learning to think in Clojure. Some more advanced books might be useful too. A good starting point is https://clojure.org/community/resources

thiru17:05:19

Cool, thank you!

Luke Zeitlin17:05:33

Joy of Clojure is my fav clojure textbook

Luke Zeitlin17:05:43

maybe a bit dated now

thiru17:05:05

8 years old 😉

thiru17:05:13

still worth a read I'm sure

thiru17:05:22

I guess I should expand a bit more on what I'm looking for. I've been writing clojure for a few years now but I never really invested time in learning it thoroughly. So I want something that will give me the most comprehensive/deep understanding of the language

Luke Zeitlin17:05:07

oh, probs just read the source code then

thiru17:05:37

ok.. that's 2 recommends for reading the source

jrwdunham18:05:34

Solve an interesting advent of code (or similar) problem in your language of choice, then solve it in clojure, then see how a pro clojurian did it, then gain insight, then repeat.

👍 1
Carlo18:05:54

A few clojurians here are very fond of the book Getting Clojure

thiru20:05:29

cool, I'll take a peek at that one

thiru20:05:17

I started reading Programming Clojure. Any chance you read that @UA7E6DU04? I wonder how you would contrast the two

jumar21:05:38

Joy of Clojure is a fantastic book - it's not a super easy read but if you have been doing clojure for a few years I really recommend it

🙏 1
practicalli-john22:05:31

http://clojure.org has a lot of articles explaining Clojure

thiru01:05:35

Thanks! Yeah I have gone through some of those in the past. I think I'd prefer to have a one stop shop explaining and going into depth. A book seems like maybe the best fit for this?

Ben Sless04:05:44

Reading the source is good All the books with Alex Miller as an author You can also read Bagwell's paper on HAMTs And Rich's talks are also an excellent resource

🙏 1
Young-il Choo00:06:30

There’s also Clojure, The Essential Reference by Renzo Borgatti, that provides detailed explanation of every concept. It’s one of those available while still being written from Manning. It’s only 1172 pages so far.😆

🙏 1
Carlo08:06:36

I second Clojure, The Essential Reference too. Probably not an introductory text, but wonderful to read after an introduction

👍 2
raymcdermott19:05:19

I recently noticed a nice trick that is actively used in clojure.core eg core_print: code is in a https://github.com/clojure/clojure/blob/clojure-1.10.1/src/clj/clojure/core_print.clj from core and it uses in-ns at the top of the file to be included in the clojure.core ns. I haven't seen this in the wild. Is it cos I haven't seen enough code bases or because it's not preferred by the community for some reason?

seancorfield19:05:21

clojure.core is a very unusual piece of Clojure code -- and it's a massive namespace -- so splitting it up is, I suspect, just a way to make it a bit more manageable when working on it. I can't imagine any real world production code ending up looking like that...

didibus19:05:39

It's not preferred because it confuses tooling and isn't always supported by tooling, even if it's totally fine in the language itself

raymcdermott19:05:39

yeah, I was thinking that it might mean that the tooling is weak / incomplete.

seancorfield19:05:17

I don't think that's the conclusion I would draw from it 🙂

seancorfield19:05:18

I find it a bit weird that https://clojure.org/reference/namespaces says

At the Repl it’s best to use in-ns, in which case the new namespace will contain mappings only for the classnames in java.lang. In order to access the names from the clojure.core namespace you must execute (clojure.core/refer 'clojure.core). The user namespace at the Repl has already done this.
I see beginners get confused by in-ns in the REPL quite a bit.

seancorfield19:05:52

Fortunately, in https://clojure.org/guides/learn/namespaces#_loading it says (after explaining the mapping from namespaces to files)

Due to this loading convention, most Clojure is structured with a 1-to-1 mapping of namespaces to files, stored in hierarchical fashion that maps to the namespace structure.

seancorfield19:05:26

And the official guide about namespaces clarifies the in-ns thing https://clojure.org/guides/repl/navigating_namespaces#_switching_to_an_existing_namespace_with_in_ns

What happens if you in-ns to a namespace that has never been created? You will see strange things happening.
Strange, indeed 🙂

raymcdermott19:05:59

ok, so weird historical edge case

raymcdermott19:05:21

that persists cos it's working

raymcdermott19:05:48

so I guess it's important for tooling to understand that files and ns are not the same thing, though they tend to be

seancorfield19:05:56

And because ns uses in-ns as well as several other low-level namespace-related functions...

seancorfield20:05:33

It's very rare for files and nses not to map 1-to-1. I can't think of anything outside clojure.core that I've seen that does that...?

raymcdermott20:05:06

no - me neither hence the question

raymcdermott20:05:09

I want to support database rather than file based tooling so anything that is unusual in this way is good to know.

raymcdermott20:05:26

I appreciate your comments @U04V70XH6

seancorfield20:05:38

We have a handful of in-ns calls but they're all in RCFs and they're like this:

(require ' :reload)
  (in-ns ')
  ...
(all from my teammate -- I don't use in-ns because my editor/REPL combo always switches to the right ns to eval code automatically)

raymcdermott20:05:25

I know until recently you also had to load the namespace in CLJS but that was fixed

raymcdermott20:05:42

"recently" being a few years ago 🙂

seancorfield20:05:18

Rich Comment Forms

1
1
seancorfield20:05:56

(comment ..) with dev-only code in it (generally). Stu Halloway coined the term because Rich uses them quite a bit 🙂

1
didibus20:05:26

I don't know, I think you could argue the tooling is incomplete, but also the idioms people ended up with tend to not split a namespace across files, and so the tooling never had to take on that additional complexity. in-nsis also harder to work with for tooling, because it doesn't have dependencies, instead you would have other calls to refer or require, so it's a lot harder to manage for tooling. in-ns is the special form and it mirrors Common Lisp more, it's more primitive and less useful. Even at the Repl, I personally use ns to switch even to existing namespaces.

didibus20:05:35

Though it looks like in-ns and ns actually both start out as the same thing, both special forms, and then ns is rebound to the core ns

seancorfield20:05:59

clojure.core does a lot of weird stuff as it is bootstrapping the language across that whole namespace...

Ben Sless04:05:10

@U04V5V0V4 how about breaking the REPL into its components? Read analyzes and inserts to the db, eval takes an id, reifies and evals

raymcdermott08:05:28

@UK0810AQ2 it's not the way I'm going but it sounds like an interesting approach!

Ben Sless09:05:35

@U04V5V0V4 are you trying to go the Unison way where terms that are alpha equivalent are semantically equivalent?

raymcdermott10:05:59

I don't know what that means

Ben Sless10:05:16

In Unison things like (fn [x] (inc x)) and (fn [y] (inc y)) are equivalent and saved/linked in the same hash (db entry) I was wondering if this was the main thrust of your question wrt saving code in a database

raymcdermott10:05:36

ah no, it's not that smart. I'm only tracking named vars per ns.

raymcdermott10:05:57

Those kind of similarities could be detected based on the data but that's downstream

raymcdermott10:05:58

the level of ambition is small: a fancier, better informed editing experience for Clojure

Ben Sless10:05:51

A good start would be saving the form as metadata 🙂

raymcdermott10:05:07

spec/conform is my weapon of choice

thheller19:05:05

pretty sure all that code predates an actual ns form but not sure

raymcdermott19:05:31

how would in-ns work back then?

thheller19:05:49

namespaces existed. just not the ns macro

raymcdermott19:05:54

ah ok - yes, I see now that the first check-in of clojure.core also used in-ns

didibus20:05:46

The issue is that the ns macro is defined in clojure.core, so you can't use the ns macro before it has been defined obviously, that's why clojure.core has to use in-ns

didibus20:05:30

Actually, it seems like ns is first available as a special form that's similar too in-ns but works as a macro, and then it gets replaced by clojure.core's ns

tomekw20:05:46

What's the best way to render user-provided Markdown with hiccup2 (that respects escaping) :thinking_face:

borkdude08:05:13

what does markdown have to do with hiccup2?

Andy Wootton12:05:15

Markdown is often rendered into HTML for WIKI web pages. This exists but I haven't used it https://github.com/mpcarolin/markdown-to-hiccup

tomekw13:05:52

@U04V15CAJ I figured it out, I guess it was too late yesterday 😅 According to Markdown spec it doesn't escape anything. And hiccup2 does, everything by default. And it's a bad idea to render as raw. So what I have to do is to escape the input first, render to Markdown, and then use raw

Drew Verlee22:05:57

@U030521UZ1N can you explain how hiccup escapes everything? As an aside, the terminology "escaped" is really weird to me given what it's about, i never thought about that description very much.

Drew Verlee22:05:19

It's just a way to have reserved functions. like & has special meaning in a url, it's not just a string.

Drew Verlee22:05:36

but what's escaping? getting free? running away?

Drew Verlee22:05:43

i guess if your the character "&" your escaping the pool of reserved words/symbols.

tomekw08:05:32

> but what's escaping? getting free? running away? I'm not native speaker, but there is no need to be sarcastic. But here you go: https://github.com/weavejester/hiccup/blob/master/src/hiccup/util.clj#L80-L88

tomekw08:05:48

I guess you should ask James Reeves why he picked this name

plexus09:05:39

Calling this escaping is common CS terminology. You're replacing special characters with escape sequences. https://en.wikipedia.org/wiki/Escape_sequence

Drew Verlee13:05:10

I wasn't being sarcastic. I was wondering about the words etymology.

👍 1
Andy Wootton17:05:45

'Escape character', Wikipedia: "Not to be confused with control character, escape sequence, or Escape key." :-/

Drew Verlee17:05:24

For me, it's easier to think of them as reserved keys/chars/function. I can't get the & table the restaurant, i can get the &foo table though and tell my friends a lie about the name.

Drew Verlee17:05:00

Idk. Communication is hard.

Andy Wootton18:05:22

I think the escape sequence was called that because the escape key was the original character used. I was just looking up why the key was called that, when I came across that helpful warning.

👍 1