Fork me on GitHub
#clojure
<
2022-09-13
>
FlavaDave15:09:10

Is there a way to use defn with intern? or any other way to get a doc string in there and have the IDE show the function signature? Example:

(create-ns 'foo)

(intern 'foo (defn bar "docs" [] "baz"))
That breaks and I wasnt exactly shocked.
(create-ns 'foo)

 (intern 'foo 'bar ^{:doc "docs"} (fn [] "baz"))
This successfully makes the function but the docstring doesnt work and my IDE wont show the signature. Any thoughts?

Alex Miller (Clojure team)16:09:10

did you read the intern doc string?

Alex Miller (Clojure team)16:09:28

"The var will adopt any metadata from the name symbol."

Alex Miller (Clojure team)16:09:46

(intern 'foo (with-meta 'bar {:doc "docs"}) (fn [] "baz"))

dpsutton16:09:47

for nrepl based IDEs this will work as they query the runtime for docs. For static based tooling this will not work (Cursive, clojure-lsp)

didibus00:09:51

If this is for a macro or something, normally I just switch ns call defn and switch back

FlavaDave00:09:24

it is for a macro

didibus01:09:19

Ya, so I don't remember perfectly, but what I've done in the past is something like:

(let [previous-ns *ns*]
  (ns foo)
  (defn bar []
  "Some doc"
  :baz)
  (in-ns previous-ns))

didibus01:09:17

I think maybe you need to wrap *ns* with ns-name or something. But this is the gist of it.

FlavaDave03:09:56

Oooooh that's a good one. I'm gonna try something like that! Thanks!

vemv22:09:57

I have an issue, worded in ๐Ÿงต

(->> rows
     (mapv (fn [row]
             (let [columns (atom {})
                   entry (into {}
                               (map-indexed (fn [i x]
                                              (let [k (-> headers
                                                          (nth i)
                                                          keyword)]
                                                (swap! columns assoc k (index->column i))
                                                (println [k (index->column i)])
                                                [k, x])))
                               row)]
               (with-meta entry {:my/columns @columns})))))

vemv22:09:04

the println is run about 50 times, with values that look good. All keys k are distinct

vemv22:09:37

but then the metadata I generate only has about 8 elements, not 50

vemv22:09:49

what could be going on? as mentioned the keys are distinct so each assoc call is not overwriting the prior entries

hiredman22:09:29

how do you know the keys are distinct?

vemv22:09:55

it's data I know very well and also I checked out the printlns again

hiredman22:09:08

how many items are in row?

hiredman22:09:50

the println is run once for each item in row, and for each row in rows

hiredman22:09:02

the swap! is the same

hiredman22:09:18

but columns only contains a value for each item in row

vemv22:09:27

row has 32 items. I verified again that all printed keys are different (32 different keys exactly)

vemv22:09:06

hmmm, the original code that didn't completely work was using transient/persistent!. now with atoms it works as intended

vemv22:09:13

does that ring a bell?

hiredman22:09:47

yeah, bashing in place on transient/persitent!

hiredman22:09:56

using them like they are a mutable collection

hiredman22:09:51

you can't just ignore the return values of like conj!

hiredman22:09:02

sometimes it returns a new thing, sometimes it mutates the existing thing

vemv22:09:02

hmmm, I was using assoc! , looks like the bang misguided me

hiredman22:09:20

all the docs on transients tell you not to do this

vemv22:09:21

not on assoc! ?

hiredman22:09:42

the transient docs https://clojure.org/reference/transients grep for "bash in place"

๐Ÿ‘ 1
vemv22:09:41

sadly the docstring didn't hint so. I can't keep the ref guide in my head for arbitrarily long

vemv22:09:51

I also specifically don't like that it the uses ! convention but it pretends to be pure. Seems an odd hybrid. :)

hiredman22:09:01

it doesn't pretend to be pure

hiredman22:09:15

it mutates things, but sometimes returns a new structure

hiredman22:09:39

like, the contract is you have to use the return value

hiredman22:09:24

easiest thing is to just not use transients ever

vemv22:09:39

> like, the contract is you have to use the return value I'll see if I can add this as an Eastwood rule, it has it easy to declare "don't use x as a side-effect"

hiredman22:09:40

they are an optimization inside things like into

vemv22:09:10

> easiest thing is to just not use transients ever yeah never was a fan but I was dragged into them lately.

hiredman22:09:21

but if the transient usage is outside of clojure.core best to assume it has this bug unless proven correct, people refuse to read the docs on transients and just say "hey, mutable collections!"

๐Ÿ™ƒ 1
hiredman22:09:46

someone implement the transient java interface on top of redis, ignoring the contract and the possibility of calling persistent! and it made the frontpage of http://lobste.rs

ghadi22:09:09

first rule of transients club is to write an algo with ordinary persistent data structures, then sprinkle transients only at the end

๐Ÿ‘€ 2
vemv23:09:30

Feel free to check out this test case, I think that's it, but you might be able to come up with some extra nuance https://github.com/jonase/eastwood/pull/442/files#diff-e26378bf60c68079448d682ee1e4918b16dd7f2e8e989c474de436cde11b176f

didibus01:09:40

If you want mutable collections, use mutable collections like Java.util.HashMap. If you want to speed up some updates to persistent collections in a local context, you can make them transient temporarily, the nice thing is they follow the same pattern as their persistent counterpart so you don't need to change your code one bit. That's why you have to use their return. They're designed to be used like persistent collections so it's easy to go from persistent -> transient with minimal code change. That's an awesome feature in my opinion.

didibus01:09:22

Also, the ! suffix started as a way to indicate something wasn't safe in a Ref transaction. The community later took to liking it to mean side-effects/impure/mutable things. But as far as I know, all core functions take it to still mean not safe in transactions.