Fork me on GitHub
#clojure
<
2022-06-16
>
syd07:06:17

Hi, am I missing something? I can’t find-versions of a library

p-himik07:06:10

org.clojure/clojure itself is not a Git library, so you can't use find-verisons for it.

syd07:06:04

I use the command on Clojure CLI version 1.11.1.1113 without error tho

p-himik07:06:28

Hmm, indeed...

πŸ‘€ 2
syd08:06:44

thank you, gonna look at it

Alex Miller (Clojure team)13:06:46

Thanks for the report, I'll get that fixed

πŸ‘ 1
Rachel Westmacott10:06:37

Does anyone know of a legitimate way to programatically differentiate between the entries in an instance of a defrecord that are declared as fields in the defrecord form and those entries that may have been assoc'd on after the fact?

Ben Sless11:06:42

You can keep an empty example record and intersect with its keys

Rachel Westmacott11:06:08

Great question! I was idly thinking about writing some helper code that could distinguish between declared dependencies in a com.stuartsierra.component component and ad-hoc fields that were added as internal implementation details.

jumar11:06:11

So I suppose you want to do this in a general case and don't have these "empty" record instances around. You could try to access them as fields or even use __extmap directly: https://github.com/jumarko/clojure-experiments/blob/master/src/clojure_experiments/records.clj#L20-L21

πŸ‘ 1
Ben Sless11:06:00

Aren't declared dependencies considered declared with the using metadata?

Rachel Westmacott11:06:08

@UK0810AQ2 by some people, yes. Others consider the fields in the defrecord form to be the declaration of what is required. Arguably they declare different dependency sets though. The defrecord tells you all the dependencies you might need for full functionality as defined by the code of the record itself, whereas the component/using form tells you what you are providing in a specific system map. You might for example use the same component type in more than one context. In particular, if you manually assoc some things onto a component and component/start it at the REPL then you might not have the metadata.

jumar11:06:58

@U0FR9C8RZ does the solution I suggested work for you?

Rachel Westmacott11:06:51

It certainly works. Tbh I'm not that keen on it though because "extmap" looks a lot like the kind of internal implementation detail I wouldn't want to build on. Thank you for your gist, though.

Rachel Westmacott11:06:15

This was more a curiosity thing than something I need to build.

Rachel Westmacott11:06:43

I also considered looking at the result of .getDeclaredFields, de-munging them and comparing them to the names of the map keys. It's using slightly more "public" data, but it still feels like a questionable hack.

jumar11:06:41

I think it's perfectly fine for the kind of question you are trying to answer. If you are looking at building a tool for public use then maybe not but I wouldn't be afraid of that approach if you decide to actually build it.

noisesmith20:06:58

(cmd)user=> (defrecord Foo [bar baz])
user.Foo
(cmd)user=> (Foo/getBasis)
[bar baz]
this may help?

noisesmith20:06:17

I'm still trying to figure out how to actually use that if all you have is an instance of Foo - my interop is rusty

noisesmith20:06:00

you can narrow things down using reflection too

(ins)user=> (-> (reflect/reflect (map->Foo {:a 0})) :members (->> (filter #(= (:type %) 'java.lang.Object))) pprint)
({:name __extmap,
  :type java.lang.Object,
  :declaring-class user.Foo,
  :flags #{:public :final}}
 {:name baz,
  :type java.lang.Object,
  :declaring-class user.Foo,
  :flags #{:public :final}}
 {:name __meta,
  :type java.lang.Object,
  :declaring-class user.Foo,
  :flags #{:public :final}}
 {:name bar,
  :type java.lang.Object,
  :declaring-class user.Foo,
  :flags #{:public :final}})
nil
user=>

noisesmith20:06:20

I used clojure.reflect/reflect (comes with core) to find getBasis

noisesmith20:06:08

if it's something done once on startup, the cost of reflection might be outweighed by the clarity it provides

noisesmith20:06:09

(-> (reflect/reflect (map->Foo {:a 0})) :members pprint) shows all the methods, but fair warning many are stubs / error when called (map methods that java expects that make no sense on an immutable object)

noisesmith20:06:36

it's too bad that getDeclaredConstructors for defrecord doesn't return a zero arg constructor

phill09:06:26

hmm... then all the code would have to worry about the "uninitialized" state as well as the "initialized" state...

Patrick Brown11:06:04

While using clojure.tools.namespace.repl/refresh blows stack with an #error containing the key {:cause "Invalid token: ::any-namespaced/keyword"}. It does this even when the namespaced keyword is inside of a comment block. Or commented out via #_ inside of a comment block. Is this expected behavior? Is there a way around it? It's certainly starting to get inconvenient. Any ideas appreciated.

magnars11:06:54

Since comment is a macro, its contents still need to be read, which is when namespace-aliased keys are resolved. You can use the fully qualified namespace :my.entire.namespace/keyword to avoid the issue, or comment it out using ;; which is ignored by the reader.

ghadi11:06:39

There's a bug in JIRA for ignoring unreadable keywords within #_

Patrick Brown11:06:56

Appreciate the knowledge. Thanks for the prompt delivery.

Ronny Li17:06:57

Hi everyone, I need to scan my CLJ and CLJS dependencies for vulnerabilities and license compliance (something like https://docs.snyk.io/products/snyk-open-source, but for Clojure). Any advice would be much appreciated!

lukasz17:06:36

Is it a one-off task? Can't speak about CLJS, but for CLJ, I run lein pom in all our projects and then used Whitesource to run the audit. Most tools like that work just fine if they assume they're dealing with Java/Maven

Ronny Li17:06:29

ah excellent, thank you!

Ronny Li17:06:50

yeah one-off is totally fine

lukasz17:06:55

if you're getting audited or if this is for a tech due diligence, most likely you'll still spend hours explaining what's going on :-)

lukasz17:06:04

but having that report def helps

πŸ‘ 1
Ronny Li17:06:13

tech due dil. And yeah, I literally just came out of a 5-hour call!

lukasz17:06:18

good luck, I hope it all goes well!

πŸ™ 1
lukasz17:06:10

(the toughest thing to explain was that you can't really do static code analysis on Clojure, beyond clj-kondo/other linters, people just assume that Java's solutions are standard - stuff like Sonar Qube etc)

πŸ‘ 1
Alex Miller (Clojure team)17:06:24

There are sonar integrations with support for things like kondo and nvd checking btw

πŸ‘€ 1
devn18:06:47

clj-holmes exists

devn18:06:56

the ruleset is not particularly large, but it is an option

devn18:06:05

lukasz, that pom option seems like not a bad one

lukasz18:06:30

I used it during SOC2 audits and when selling my biz, def worked as far as the technical part was concerned

devn18:06:20

yeah was going to add I did actually use it for getting through security review a couple times, but when I compare it to codeql + typescript definitions from GitHub for example, it's extremely light. It was accepted as sufficient evidence, but I personally wouldn't mind a bit more comprehensive suite

Kelvin20:06:39

There's https://github.com/rm-hull/nvd-clojure which is based off of the Java DependencyCheck library

πŸ‘ 1
practicalli-johnny20:06:43

I use https://docs.snyk.io/, its exactly like https://docs.snyk.io/ πŸ˜† although I havent checked how comprehensive the reports are (but then I havent had to do an audit) I suspect it covers a similar amount to nvd-clojure

Drew Verlee22:06:43

within a cljc ns can you require-macros the same ns? e.g (ns foo #?(:cljs (:require-macros [foo :refer [bar]))) I'm running this in shadow and it's telling me it can't find foo. The project is older so maybe this was valid at some point and isn't now? or it was built differently...

Drew Verlee03:06:12

The answer appears to be yes, though there is also refer-macros which might be more concise (according to the docs).

Patrick Brown22:06:32

Clojurians, I'm finding this one interesting. (seq? [:vector :aint :iSeq]) => false (sequential? [:but :is :sequential]) => true So what gives? Is there a reason why vectors don't implement ISeq? I'm sure there's a well thought out one, but I don't get it.

hiredman22:06:36

why would they?

hiredman22:06:40

a seq is a functional interator

hiredman22:06:29

lists happen to also be seqs, because the methods for using a seq (first, rest, car, cdr, whatever) are the same for seqs and lists

hiredman22:06:43

vectors don't really have a rest operation

hiredman22:06:16

(you can kind of kludge one using subvec, but that retains references to the original vector in a way that rest on a seq doesn't)

phronmophobic22:06:46

If it helps, I don't think it's that obvious. Someone recently posted an old article that talked about some of the underlying ideas, https://insideclojure.org/2015/01/02/sequences/

βž• 2
Max22:06:34

Agreed, don't think it's particularly obvious at all

Patrick Brown22:06:00

Yup, definitely worth a read. I think the portion about laziness might get me over some confusion as well.

phronmophobic22:06:43

I was also surprised, at first, that vectors don't implement ISeq (it's not to say that there aren't very good reasons. there are).

Patrick Brown22:06:07

I lost you at first and started to get it at vectors not having rest operation.

hiredman22:06:10

have you used a language with external iterators? (java for example)

Patrick Brown22:06:36

Can't say I know any language very well outside of Clojure. Up until recently I just wrote code for fun.

hiredman22:06:46

so java has iterators for traversing collections, like if you have a set in java, and you wanted to process each element in it, you could do it like

... it = theset.iterator();
while(it.hasNext()) {
  whatever(it.next());
}

hiredman22:06:58

you can uses iterators in clojure like

(let [it (.iterator theset)]
  (while (.hashNext it)
    (whatever (.next it))))

hiredman22:06:12

or in in a way that consumes stack space, but will make the pattern clearer

((fn thisfn [it] (when (.hasNext it) (whatever (.next it)) (thisfn it)) (.iteator theset))

hiredman22:06:08

or with a seq instead of an iterator

((fn thisfn [s] (when (seq s) (whatever (first s)) (thisfn (rest s))) (seq theset))

hiredman22:06:02

seqs are a view for iterating over some data (often a collection), like an iterator

Patrick Brown22:06:15

OK, now I'm showing some lack of understanding. What is the relationship between calling .hasNext .Next, loop/recur and peek/pop? I struggle at times with doing things like that and often write code, change, write more, until I accidentally get things working.

hiredman23:06:24

a java iterator is a mutable cursor, hasNext asks if there are more items, next returns the next item and moves the cursor forward one

hiredman23:06:59

those things don't relate to loop/recur (looping) in any particular way, except that usually when you use an iterator you are looping over calling those methods

hiredman23:06:29

peek and pop are functions on stacks (both lists and vectors are stacks)

Patrick Brown23:06:03

To make it practical, a good pattern to practice would be loop/recur with peek and pop which will cover me for my sequential needs?

hiredman23:06:07

peek and pop work on stacks (lists or vectors), so they will cover you for stacks, but it is much more common to be using seqs, which is done with first and rest

Patrick Brown23:06:30

ok, first and rest I use quite frequently.

Patrick Brown23:06:27

I'm following this code until I get to theset.

((fn thisfn [s] (when (seq s) (whatever (first s)) (thisfn (rest s))) (seq theset))

hiredman23:06:58

running example, supposes a set collection

Patrick Brown23:06:58

You've been a big help. Right now I'm writing a function to store vectors and lists in Datomic. I've been naming my attributes and functions as seq, :seq-index :seq-value :seq-type. What would you name it in place of seq to be more accurate?

Drew Verlee03:06:54

How are you storing a vector in datomic?

Patrick Brown00:06:37

Everything is a string, with the type annotated, maps are stored with a ref-many attribute of entries containing keys and vals annotated with a type attribute, vectors/lists are stored with ref-many items annotated with an index attribute. Nesting is done by making additional passes to replace the string collection value with a ref. Largely because I couldn't figure out how to postwalk or do anything clever. It's all fairly simple, no magic.