Fork me on GitHub
#beginners
<
2023-12-06
>
Daniel Basner01:12:34

I have been struggling with with vscode/calva/clj-kondo setup and I cannot tell why I am getting the warning Namespace name does not match file name: craigslist-art-gallery.core clj-kondo(namespace-name-mismatch) in the file src/craigslist-art-gallery/core.clj since the filename and ns appear to match. Paring it down to a very minimal project directory containing nothing but a core.clj file that only creates the craigslist-art-gallery.core ns and a deps.edn that specifies src under the :paths key has not clarified what could be causing the issue. Classpath seems to be correct. Context in thread.

Daniel Basner01:12:50

here is some context on what I have: a namespace in a file and a deps.edn that I would expect to properly set up the classpath results in the clj-kondo CLI to mark a warning about this mismatch:

(base) ➜  craigslist-art-gallery> pwd
/Users/dbasner/workspace/craigslist-art-gallery
(base) ➜  craigslist-art-gallery> cat deps.edn
{:paths ["src"]
 :deps {org.clojure/clojure {:mvn/version "1.11.1"}}}
(base) ➜  craigslist-art-gallery> clojure -Spath
src:/Users/dbasner/.m2/repository/org/clojure/clojure/1.11.1/clojure-1.11.1.jar:/Users/dbasner/.m2/repository/org/clojure/core.specs.alpha/0.2.62/core.specs.alpha-0.2.62.jar:/Users/dbasner/.m2/repository/org/clojure/spec.alpha/0.3.218/spec.alpha-0.3.218.jar
(base) ➜  craigslist-art-gallery> cat src/craigslist-art-gallery/core.clj                                                             
(ns craigslist-art-gallery.core)
(base) ➜  craigslist-art-gallery> clj-kondo --classpath "$(clojure -Spath)" --lint /Users/dbasner/workspace/craigslist-art-gallery/src/craigslist-art-gallery/core.clj
/Users/dbasner/workspace/craigslist-art-gallery/src/craigslist-art-gallery/core.clj:1:5: error: Namespace name does not match file name: craigslist-art-gallery.core
linting took 35ms, errors: 1, warnings: 0

hiredman01:12:05

File and directory names should contain _ where namespace names contain -

👍 2
Daniel Basner01:12:37

I’ve spent so long staring at this, thank you hiredman I appreciate it!

phill11:12:53

The linter's message could be more specific! Why not raise a question in #CHY97NXE2?

Georgi Stoyanov07:12:52

Hi folks. I hit a problem with https://github.com/clojure/java.data Long story short - we are parsing some data from k8s java client to edn, change it and then want to create java instance from that map. Here is my simple code

defmethod data/to-java [V1Job clojure.lang.APersistentMap] [clazz props]
  (doto (V1Job.)
    (.apiVersion "batch/v1")
    (.kind "Job")
    (.metadata (data/to-java V1ObjectMeta (:metadata props)))
    (.spec (data/to-java V1JobSpec (:spec props)))))
But inside the spec (V1JobSpec) we have a template (V1PodTemplateSpec) and inside of it there is spec (V1PodSpec) where we have
......
containers: clojure.lang.LazySeq@d094320b
......
Then when I run this code in k8s I have
{"reason":"FieldValueRequired","message":"Required value","field":"spec.template.spec.containers[0].name"},
{"reason":"FieldValueRequired","message":"Required value","field":"spec.template.spec.containers[0].image"}
but in the edn i do have the name and the image. Is there a way I can force the evaluation of this LazySeq that was assigned to the java object? Or not create it at all?

seancorfield18:12:38

Sounds like it's trying to convert that to a string for printing? Can you provide a bit more context for that specfiic part of the to-java process? Can you call vec on the :containers fields?

Georgi Stoyanov07:12:07

@U04V70XH6 vec is solving the problem, yes, I was just worried that for other objects we might have the same problem. I’m using the to-java from java.data and when I override it it’s just the part that I shared, nothing more and tbh I don’t really know how this lib works.

Andrei Stan18:12:23

hello guys, i am learning about concurrency , i have started reading The Java™ Tutorials and write the java code in clojure; so far i reached the "producer - consumer" concept, but the problem is that my threads are blocking each other somehow the link for the lesson is here : https://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html my code is here: https://github.com/sandre1/clj-training/blob/main/java-concurrency/src/concurrency/producer_consumer.clj You can start calva and execute producer-consumer function I tried with clojure locking function, locking different Object. for synchronized methods, without success Expected result:

Start
...
(some println-s for feedback)
...
MESSAGE RECEIVED: Mares eat oats
MESSAGE RECEIVED: Does eat oats
MESSAGE RECEIVED: Little lambs eat ivy
MESSAGE RECEIVED: A kid will eat ivy too
DONE!
Stop

jpmonettas19:12:56

on your clojure repl, you can hit Ctrl-\ to see a thread dump, where you can check all the threads stacks and see if they are waiting for a lock for example, which can help you debug this kind of code

Andrei Stan19:12:00

ctrl+\ just opens the current tab in a new tab

Andrei Stan19:12:13

do you have an extension for the thread dump, maby?

jpmonettas19:12:26

or if you use a debugger like http://www.flow-storm.org/ you have features like the https://flow-storm.github.io/flow-storm-debugger/user_guide.html#_timeline_tool to help you debug those kinds of things

jpmonettas19:12:38

ctrl+\ just opens the current tab in a new tabthat should be in a terminal repl

jpmonettas19:12:41

also you can use https://visualvm.github.io/ to connect to any jvm process and do a thread dump, heap dump, monitor you GC and more

jpmonettas19:12:58

visualvm is what I tend to use for thread dumps, since you just run the program, double click on your process then click the Threads tab, and there you have a Thread Dump button

Andrei Stan19:12:26

ok, thank you. i will check it

hiredman20:12:26

clojure functions are Runnables so you can pass them directly to things like the Thread constructor without needing to reify Runnable

hiredman20:12:42

your issue has nothing to do with concurrency

hiredman20:12:16

you have an immutable data structure and are always printing out the first thing in it, and since the datastructure is immutable the first thing is always the same misread

hiredman20:12:19

it is likely https://github.com/sandre1/clj-training/blob/main/java-concurrency/src/concurrency/producer_consumer.clj#L55 that is a race condition, you are only continuing to loop if the message returned by take is the same as the value of message-global, which take just woke up the publisher to overwrite

hiredman21:12:59

in general I would recommend, if you are following the java tutorial, to stick to it more closely, e.g. make something that is a "Drop" and make a new drop and pass it in to the thing that makes producers and consumers. that will help avoid various things that can happen in the repl when you have global locks (you have an old thread running, holding the lock, then try to start a new thread and nothing happens)

hiredman21:12:31

or you could just go straight to using https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/SynchronousQueue.html which is almost but not entirely exaclty Drop (drop is a blocking queue with a internal buffer / capacity of 1, SynchronousQueue has a capacity of 0)

Andrei Stan22:12:25

thank you for the review, i modified part of the code so it consumes all the messages from the producer. still i have a problem with the threads, one/both are not closing. so after the threads are started, no "Stop" will print https://github.com/sandre1/clj-training/blob/main/java-concurrency/src/concurrency/producer_consumer.clj

ric23:12:11

Can someone help me understand programming with streams? I've seen code like this in advent of code:

(let [in (line-seq (java.io.BufferedReader. *in*))]
  (println "Part A:" (transduce xf conj '() in)))
I don't understand how/when the program considers end of stream, does it wait for a explicit end, similar to EOF in a file?

phronmophobic23:12:00

line-seq returns a lazy sequence of lines. Underneath the hood, line-seq uses the .readLine method from BufferedReader. It keeps reading until readLine returns null which is how it signals that it's done.

phronmophobic23:12:15

For unix-like systems, all file operations eventually boil down to what the operating system offers which is almost always https://www.man7.org/linux/man-pages/man2/read.2.html. I've found that learning a bit about the posix C APIs to be helpful since those are the operations every programming runtime eventually boils down to.

phronmophobic23:12:54

Some languages offer higher level APIs on top and some languages even manage not to screw up (but some still do. nodejs 👀).

ric23:12:23

Thanks, I'll read more about the underlying impl. Does it offer any advantage to (string/split-lines (slurp "a.txt")) if I'm just going through line by line with transduce?

phronmophobic00:12:01

Potentially. For small inputs, it doesn't really matter. For large inputs, using line-seq + transduce would allow you to do garbage collection as you go so that you don't have to fit the full file in memory. The example code you gave with transduce is still combining everything in memory, but if xf was filtering or some other reduction was happening, than it could be more memory efficient.

phronmophobic00:12:42

Again, for small programs and inputs, it doesn't really matter. However, here are some general tips that might help for scaling to larger programs and inputs: • Don't mix lazy sequences with I/O • Don't use slurp • Check out with-open • Check out iteration • Transducers work great even in cases where there might be I/O or side effects

ric00:12:30

ah that's quite helpful!

ric00:12:39

I think I understood about my example with tranducer with conj not mattering, so something like (transduce xf + ...) would matter right? some reduction f that doesn't hold onto the head

👍 1
phronmophobic00:12:31

Yea, but even with (transduce xf conj '() in), if xf was something like (filter (constantly true)) or another transducer that filtered most of the content, then it could matter there too.

phronmophobic00:12:26

Also, another tip is that if you're using transducers to produce a collection, then into will be shorter and more idiomatic. For example (into '() xf coll).

🆒 1
phronmophobic00:12:09

Not that matters, but '() doesn't need to be quoted. The empty list () evaluates to itself since there's nothing to call.

👍 1