beginners 2020-12-21

@seancorfield so i have something to explore to do here regarding testing macros .. my test worked fine in the repl, but not when running lein test - I fixed that by changing the quote for macroexpand from ' to ` (hard to write in slack)

Hmm, regular ' should work but your tests need to also have the quoted expected form.

dev=> (require '[clojure.test :refer [deftest is]])
nil
dev=> (macroexpand '(when a b))
(if a (do b))
dev=> (deftest when-test
        (is (= '(if a (do b))
               (macroexpand '(when a b)))))
#'dev/when-test
dev=> (when-test)
nil
dev=> 

Yup, just verified that works with lein test @st3fan

(! 999)-> lein new st3fan
Generating a project called st3fan based on the 'default' template.
The default template is intended for library projects, not applications.
To see other templates (app, plugin, etc), try `lein help new`.
(! 1000)-> cd st3fan/
(! 1001)-> vi test/st3fan/core_test.clj 
(! 1002)-> cat test/st3fan/core_test.clj 
(ns st3fan.core-test
  (:require [clojure.test :refer :all]
            [st3fan.core :refer :all]))

(deftest when-test
  (is (= '(if a (do b))
         (macroexpand '(when a b)))))
(! 1003)-> lein test

lein test st3fan.core-test

Ran 1 tests containing 1 assertions.
0 failures, 0 errors.

How do I deal with Unhandled java.lang.NoClassDefFoundError when calling a function from a Clojure library that uses a Java library?

It depends how and where and what class it says isn't defined

The message on the exception will say which class, the stack trace will tell you where

org/apache/commons/compress/utils/InputStreamStatistics Do I need to import it somehow?

You don't need to import it, but it needs to be on the class path, the exact details will depend on the tools you are using

Do you mean lein?

If it is a dependency of the library you using, typical whatever tools you are using will pull in the entire dependency tree and build a class path from it

Yes, lein or boot or clj or maven or even by hand

Could you link me to how I can do this? I've a feeling it might be related to me trying the library by cloning it - am trying https://github.com/zero-one-group/fxl btw

@zackteo if you're using lein, you have to put [zone.one/fxl "0.0.5"] in your :dependencies in your project's project.clj

and then run lein deps in the directory of your project to update your dependencies.

@ricardolopez.zagal I am running the code from within the project. It seems to have to do with cider actually ... am able to run my code within lein repl and using calva

@zackteo Wait, are you running the code within the project that you cloned?

@zackteo You don't need to clone dependencies using git Lein does it for you from clojars using lein deps if you you create a project using lein new foo , and you put [zone.one/fxl "0.0.5"] inside project.clj, and run lein deps, you'll be able to use the repl and to make your project using that dependency It's way more practical than cloning the dependencies from git, specially if you have to use multiple dependencies.

No no I think You got it confused πŸ˜… my bad. Am trying to work on the library itself

And my mini-test for the function seems to work within a basic lein repl and from calva. So it appears that cider might be doing something that causes some issues :x

No worries πŸ™‚ Now I know about using lein deps after updating dependencies

Okay got it fixed ... Think it has to do with me not updating cider because I was on emacs native-comp and doom emacs stop supporting the version I was on

How do I invoke this code blocking?

(go (let [response (<! (http/get ""
                                 {:with-credentials? false
                                  :query-params {"since" 135}}))]
      (prn (:status response))
      (prn (map :login (:body response)))))

is this cljs?

I don't want any async stuff, it's just that the cljs-https requires this

you can't. can't block in javascript

Hello, what do you think is the better representation of database structure. Both ways have trade-offs, no?

{:db1
  {:tables 
    {"public.people" 
      {:columns {"id" {:data_type "int"}
                 "name" {:data_type "string"}}}}}}
or (more clojure.jdbc native)
{:db1 
  {:tables [
     {:table_name "public.people" 
      :columns [
        {:column_name "id" :data_type "int"} 
        {:column_name "name" :data_type "string"}]}]}}
Thanks

Alex Miller (Clojure team) 2020-12-21T14:59:49.156800Z

sets and maps are better choices for lookup than vectors

I did not consider to use sets for better lookup. Thank you for the idea.

@louis77 has joined the channel

@nicke.claesson has joined the channel

is there a way in clojure.math.combinators to get all of the permutations by taking one from each list in a list-of-lists? for example:

;; getting from this
[[:a1 :a2] [:b1 :b2]]

;; to these
:a1 :b1
:a1 :b2
:a2 :b1
:a2 :b2

I've considered getting the permutations of the indexes, like (permutations [0 0 1 1]) and then using them as indexes in each inner list, so when theres 3 inner lists each with 2 items it'd be the permutation of [0 0 0 1 1 1] as indexes

Are you looking for cartesian-product?

facepalm yes! thanks

πŸ‘ 1

literally couldn't be any clearer in the description > ; all the ways to take one item from each passed-in sequence

@pavel953 has joined the channel

@elichaiml has joined the channel

what is the most idiomatic or preferable way to read a file in Clojure, using slurp or io/reader?

Either; slurp loads it in memory and generally is ok with small files; With reader you can stream operations.

πŸ‘ 2

slurp is using http://clojure.java.io/reader internally in with-open context so slurp will close reader after consuming all the content. if you are using http://clojure.java.io/reader explicitly do not forget to close the reader after you finish processing otherwise this could lead to memory leaks

πŸ‘ 3

@e-mail has joined the channel

Exception in thread "Thread-8" java.io.IOException: Stream closed
        at java.io.BufferedReader.ensureOpen(BufferedReader.java:122)
        at java.io.BufferedReader.readLine(BufferedReader.java:317)
        at java.io.BufferedReader.readLine(BufferedReader.java:389)
        at clojure.core$line_seq.invokeStatic(core.clj:3091)
        at clojure.core$line_seq$fn__5970.invoke(core.clj:3092)
        at clojure.lang.LazySeq.sval(LazySeq.java:42)
        at clojure.lang.LazySeq.seq(LazySeq.java:51)
        at clojure.lang.LazySeq.equals(LazySeq.java:121)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at clojure.lang.Reflector.invokeMatchingMethod(Reflector.java:167)
        at clojure.lang.Reflector.invokeInstanceMethod(Reflector.java:102)
        at malachite_mk1.core$concurrent_collision$fn__318.invoke(core.clj:118)
        at clojure.lang.AFn.run(AFn.java:22)
        at java.lang.Thread.run(Thread.java:748)
#object[java.lang.Thread 0x64864f7e "Thread[Thread-9,5,main]"]
Oh boy, this is going to be fun to debug... /s

Alex Miller (Clojure team) 2020-12-21T15:00:35.157300Z

usually laziness combined with io

Alex Miller (Clojure team) 2020-12-21T15:00:56.157700Z

like a with-open that returns a lazy seq

oh, yeah that's literally the thing I'm trying to do

Alex Miller (Clojure team) 2020-12-21T15:02:16.158700Z

I've seen this movie

Like, I'm trying to read a file line by line This works fine in the non-concurrent version of the function, but it returns this error in the concurrent one πŸ˜•

Alex Miller (Clojure team) 2020-12-21T15:03:06.160700Z

either return something eager (often with into ) or invert the control and pass the thing you want to do with the lazy seq into the with-open so it's completed in scope

Alex Miller (Clojure team) 2020-12-21T15:03:53.161100Z

well, if you're doing io and concurrency, you need to think carefully about that

Alex Miller (Clojure team) 2020-12-21T15:04:40.161800Z

a common pattern is to have one thread that just reads and queues work, then closes when done reading

Alex Miller (Clojure team) 2020-12-21T15:05:08.162400Z

and "queue" could mean to use future to spin jobs, or use a Java executor, or put work on a core.async channel

;; I have a question similar to domino's, but i am trying to understand lazy-seqs and not run into OOM issue. ;; Say I read the file in memory. I now need to transform/parse the data and then put this data into multiple sinks (database/streamin platform/search engine ...). IE, all the data needs to end up in all the sinks. ;; So i do this with map/filter and make it lazy. In the end I need to realize the sequence in order to store it into the sink(s). Form what i understand about lazy-seqs, i need to avoid holding onto the head of the lazy-seq. ;; But I am not sure what this really means. ;; In this example, am i holding onto the head of the lazy-seq? -- ;; sinks are partial functions which are configured with database config info

(defn transform-data [file-data]
  (->> file-data 
       (map ransform1)
       (map transform2)
       (filter filter1)
       (map transform4)))
;; I think I am holding onto the head here. When I go an sink the data into the first sink, I am realizing the data and it cannot get garbage collected because there are still other sinks remaining to process the data . Is this correct?
(def sink-all-data [sinks data]
  (doseq [sink sinks]
    (sink data)))
(sink-all-data partial-sinks (transform-data (data-from-file "/foo/large-file.txt")))

you are not holding onto the head, because each time you consume a new element from "file-data", the previous element can be freed

the head of a lazy seq is the first element, there's nothing in that code that points to the first element of the seq and escapes scope

now file-data itself could be the head of a lazy seq, that means the culprit isn't the code you shared, it's the code that creates a lazy-seq from the input and returns the first element

> Say I read the file in memory. the point is to avoid this - to find a way that the entire file doesn't need to be in memory

we use core.async channels for this

I'll look into that, thanks for the hint! πŸ™‚

At my current work, the variables we use seem to be max 3 characters, like lid, pid, mv etc. which I find are uninterpretable. When querying about it, I was told it was because we use the NoSQL document storage and short names like that help save cost. Can anyone with the relevant experience (Mongo or Azure CosmosDB) comment on that rationale?

@amir953 has joined the channel

What is the preferred way to handle dates in clojure?

I use atm, but if I was to do anything new, I would probably just use the java date time classes directly (if on java 8+) as they are nice to use and interop works really well.

πŸ‘ 2

I was looking at that library as it seems nice but thought that maybe I ask first if people use any libraries or directly java8 api

I think using the java8 interop is the preferred way now, especially if you're greenfield

yeah, I would hit the java 8 apis directly now (or java 11, as I'm on that jdk)

I may even spend some time these holidays to do that

Ok, maybe I’ll try that as well, thanks πŸ™‚

you're most welcome

I asked this question in a thread. Sharing it with the channel.

@slack1171 has joined the channel

@popeyepwr has joined the channel

Team, (re-matches #"^[a-z\-]+$" "abc--") will give us the result, But if i send 2 hypen it should return nil, How can I achieve this

(re-matches #"^[a-z]+\-$" "abc-")

assuming you want to match on a string with an arbitrary combination of letters plus a single hyphen at the end.

πŸ™Œ 1

Is it possible to run a public static main method from a generated class from within a repl?

yes, (ClassName/main (into-array String [arg1 arg2 ...]))

Whoa so you have to have a String array even if its empty?

you can provide an empty string array, but varargs are treated as arrays on a byte code level, and unlike java clojure makes no attempt to hide this

I might be misremembering, shouldn't be hard to try both

(defn get-user-books
  "Retrieves a user's books"
  [user consumer token]
  (for [i 1
        books {}]
    (let [response (obtain-books i)
          updated-books (conj books response)]
      (if (< 50 (count response))
        updated-books
        (recur updated-books (inc i))))))
This code fails to compile with Can only recur from tail position but isn't recur the last statement?

Alex Miller (Clojure team) 2020-12-21T20:19:00.181Z

do you mean for there?

Alex Miller (Clojure team) 2020-12-21T20:19:10.181200Z

or did you mean loop

Hi! It’s possible to use a private git repo with deps.edn?

Alex Miller (Clojure team) 2020-12-21T20:40:45.183200Z

yes

πŸ™ 1

@giovanni.damelio has joined the channel