Fork me on GitHub
#beginners
<
2022-08-03
>
Ben Lieberman16:08:51

java interop Q: I'm trying to generate a stream of dates like so (apparently wrong):

=> (def a-list-of-dates (. LocalDate (datesUntil (. LocalDate now))))
and I get:
Syntax error (IllegalArgumentException) compiling . at (REPL:1:22).
No matching method datesUntil found taking 1 args for class java.time.LocalDate
but browsing the Java docs the only reason given for an IllegalArgumentException is "if end date is before this date". Which clashes not only with my java-ignorant intuition (is LocalDate using the Unix epoch or something like it?) but also with what the Java docs show, namely that there is such a datesUntil method on the LocalDate class that takes one argument

dpsutton16:08:14

https://docs.oracle.com/javase/9/docs/api/java/time/LocalDate.html#datesUntil-java.time.LocalDate- this is an instance method. So you need (.datesUntil <instance> <end-exclusive>)

dpsutton16:08:49

(.datesUntil (LocalDate/now) (LocalDate/parse "2022-12-25")) -> LocalDate.now().datesUntil(then)

dpsutton16:08:53

(iterator-seq (.iterator (.datesUntil (LocalDate/now) (LocalDate/parse "2022-12-25"))))

๐Ÿ™Œ 1
sheluchin16:08:55

Given a vector of single-entry maps, what's the best way to get a list of the values?

pppaul18:08:14

(map val vec-of-mapentries)

pppaul18:08:09

val works on map-entries, vals works on maps. (map val ... is not very common, and it'll break when you aren't using map-entries

sheluchin18:08:18

(map val [{:x 1} {:x 2}])
=> ExceptionInfo
Error printing return value (ClassCastException) at null (REPL:1).

pppaul18:08:03

i was incorrect in my assumption of how map would handle single entry maps

pppaul18:08:35

(mapcat vals ...) is better

sheluchin18:08:58

Yes, I thought map would convert each map to a set of map entries as well.

pppaul18:08:50

it does if you do (map val {})

pppaul18:08:27

which is very similar to update-vals or update-keys

dpsutton16:08:29

(mapcat vals coll)

sheluchin16:08:53

Ah, of course. It doesn't matter how many are in each one. Thanks!

๐Ÿ‘ 1
dpsutton17:08:20

if the maps all have a single key (not necessarily specified as such in the original question) you could (map :that-key coll)

gratitude-thank-you 1
Ben Lieberman18:08:48

really weird error running clj -X:deps mvn-install :

Execution error (FileNotFoundException) at clojure.tools.cli.api/read-pom-in-jar (api.clj:357).
Jar file not found: 
and that's it, a blank line apparently indicating no JAR file at all

Alex Miller (Clojure team)18:08:26

mvn-install is for installing a jar you have into the Maven repository, which you usually don't need to do (usually by referring to it as a dep it is automatically downloaded)

Alex Miller (Clojure team)18:08:51

can you clarify the full command you ran and what you're trying to do?

Ben Lieberman18:08:18

I have a deps.edn with these contents:

{:deps
{org.clojure/core.async {:mvn/version "1.5.648"}}
{org.clojure/data.json {:mvn/version "2.4.0"}}}
and I was under the impression that in order for those to be available when I run clj that I have to install them using mvn-install

Ben Lieberman18:08:40

which I did but I get the above error

Ben Lieberman18:08:01

I could've sworn that previously I used clj -X:deps mvn-install to add core.async to my classpath and make it available in the REPL but I wouldn't stake my life on it

Chase18:08:12

You should be able to just run clj and it will download those deps before starting the repl

Alex Miller (Clojure team)18:08:55

correct, you don't need to call mvn-install here

Ben Lieberman18:08:38

I don't see any downloads happening when I start the REPL and I get ClassNotFoundException when I try to require the deps

Alex Miller (Clojure team)18:08:05

you may already have those downloads in your .m2 so they don't need to be downloaded

Alex Miller (Clojure team)18:08:47

they would be at ~/.m2/repository/org/clojure/core.async/1.5.648/core.async-1.5.648.jar for example

Alex Miller (Clojure team)19:08:10

you can check your classpath with clj -Spath

Alex Miller (Clojure team)19:08:25

what's the actual repl invocation and response you're seeing?

Ben Lieberman19:08:49

just plain

clj
Clojure 1.11.1
user=>

Ben Lieberman19:08:18

and it does appear that data.json is on my classpath as you said

Alex Miller (Clojure team)19:08:24

and the thing that causes the error

Ben Lieberman19:08:49

user=> (require [org.clojure/data.json :as json])
Syntax error (ClassNotFoundException) compiling at (REPL:1:1).
org.clojure

Alex Miller (Clojure team)19:08:11

just in general, a good recipe for asking for help to make it easy for others to help is: I want to do X. I did Y. I got Z, which is wrong/confusing/etc

Alex Miller (Clojure team)19:08:53

the namespaces in an artifact are different than the name of artifact itself (which is confusing!)

Alex Miller (Clojure team)19:08:04

and they don't even necessarily have any relationship

Alex Miller (Clojure team)19:08:26

here you'd want:

(require '[clojure.data.json :as json])

๐Ÿ’ฏ 1
Alex Miller (Clojure team)19:08:03

how would you know that, you might ask... and the answer is, only by reading the documentation

Ben Lieberman19:08:35

duly noted, on all counts. I will do that more studiously in the future. Thanks a lot for your help

Alex Miller (Clojure team)19:08:33

also note that I quoted the vector passed to require - this is data passed to a function so to avoid evaluating the symbols inside, it needs to be quoted (which means "read, but don't evaluate")

Ben Lieberman19:08:59

is there a reason why there is a divergence between artifact naming conventions? Like something to do with the reader syntax? or is it just that there is no hard rule and so things just went that way

Alex Miller (Clojure team)19:08:27

jars / artifacts are just containers to hold code

Alex Miller (Clojure team)19:08:58

in the early days of Java, there was never any established linkage between how to name / reference libraries and the code inside

Alex Miller (Clojure team)19:08:32

there was no package/dependency manager, and it was the wild west

Alex Miller (Clojure team)19:08:20

eventually Maven established some conventions, but no one ever created any hard relationship or self describability for jars (beyond just looking at what's in them)

Alex Miller (Clojure team)19:08:26

Clojure is really a source-based language with a convention for lookup, but again, basically relied on Java's ecosystem for publishing and consuming artifacts containing code

Alex Miller (Clojure team)19:08:50

so, missed opportunities at multiple points in the timeline

Ben Lieberman19:08:24

interesting history :thinking_face: maybe not the choices I would make but I know very little indeed

Alex Miller (Clojure team)19:08:12

I think figuring out library deployment and consumption should probably be on the list of things a language does very early in it's life, otherwise you end up stuck with ad hoc decisions

Alex Miller (Clojure team)19:08:47

I think there is more Clojure can do here though and it's something we've been kicking around for many years

Ben Lieberman19:08:51

the only other language I use with any degree of regularity is Rust since I'm basically a hobbyist and I am very much accustomed to cargo allowing me to not really think about anything re: dependency management, it's very straightforward

sheluchin18:08:41

I find it surprising that both of these work:

((fn [{:keys [:x]}] x) {:x 1})
((fn [{:keys [x]}] x) {:x 2}))
Is either one preferred?

sheluchin18:08:48

Vestigial, eh? ๐Ÿ™‚

sheluchin18:08:30

Interesting that there's a linter in kondo for it. I first spotted the with-colon variety in the kondo code. I suppose if there's a linter for it and it's somewhat of an artifact, the without-colon variety should be preferred. But I think using the colon would offer some benefit when searching the code base for all instances of a keyword.

pppaul18:08:52

this is the first time i've seen this form of :keys

Alex Miller (Clojure team)19:08:47

the latter is preferred

Alex Miller (Clojure team)19:08:32

the keyword form was added to support use of autoreferred keywords (`::k`, ::n/k) but those are now better supported via ::keys or ::n/keys

sheluchin19:08:16

Thanks for the confirmation.

Ross Duncan19:08:03

Hello! Im looking for any internet resources that elucidate the power and productivity of REPL driven development. This is for my own benefit, but also to refer colleagues who havent seen it before and havent yet got a vision for what it is. Its been a couple of years since I last looked for this sort of content, at which time I think the best I had found was Eric Normand's paid content, and even better was Stuart Halloway's June 2017 talk to Chicago Clojure meetup. Does anyone have any other good references beyond these? Thx in advance!

Jacob O'Bryant19:08:08

This is a good one from the illustrious @U04V70XH6: https://www.youtube.com/watch?v=gIoadGfm5T8

๐Ÿ’ฏ 1
zakkor20:08:40

How come this pair of functions is called some-fn and every-pred, instead of one of them being some-pred or every-fnfor symmetry?

pppaul20:08:26

just some weird stuff in clojure. sometimes names are well designed, sometimes not.

seancorfield20:08:44

some-fn returns the first result of applying each function in turn -- so it will return "logical true"; every-pred returns true if everything returns "logical true".

seancorfield20:08:35

But, yeah, some of this is historical quirks. Like we have every? and some -- but any? means something very different.

loganrios20:08:11

What causes Clojure/Java to try to load *.tmp files from $TMPDIR on MacOS, and how can I force it to not do that? It's happened occasionally with a few different projects--I'll open a REPL and it will either crash on start or on calling some function with an error that always looks like this:

Execution error (UnsatisfiedLinkError) at java.lang.ClassLoader/loadLibrary (ClassLoader.java:2398).
Can't load library: /var/folders/55/cthyrgtx75z0c3185j99qsx80000gn/T/jna13236126920257902248.tmp
Frustratingly, I can't ever deliberately induce it or repro on other machines--it only seems to occasionally happen when I interrupt CIDER from starting a jack-in, but then it will affect even command-line REPLs started with clj or lein repl. I suspect this is a Java-ism, since most of the SO threads and other help I've seen reference something called a JNI, but I am lost about how to clear or reset this, since reinstalling clojure/tools/clojure, leiningen, and even openjdk via Homebrew and purging the .m2 directory hasn't worked. Any guidance is appreciated simple_smile

loganrios20:08:47

@U0NCTKEV8 (moving to thread)--is there a good way to narrow down which library is at fault, and/or figure out how to reset it? I suppose if all else fails, I can try analyzing the dependencies one by one, too.

hiredman21:08:07

the stack trace will tell you what code is calling loadLibrary

loganrios21:08:00

Sounds good, thanks for the help! I will dig a little deeper and see if I can find the problem.

seancorfield21:08:14

@U03DKTAF52P I'm definitely curious to hear what you find and which libraries seem to be doing this. @U0NCTKEV8 Any idea how to clean things up once they get into a bad state like that, or is it just a case of restarting the REPL and letting it finish loading?

hiredman21:08:44

I am not sure, it will depend on what is actually doing the loading and what it is trying to load

loganrios21:08:33

This has happened a couple times across a couple projects for me, now--once on a Shadow-CLJS React Native/Expo project, and again as I'm currently working through LambdaIsland's Buddy tutorial (so it's possible that it's a my-machine-problem). Both have had a large stack of their own dependencies. Unfortunately, the issue continues across multiple restarted REPL sessions, so I'm wondering if it's something that's being saved into some hidden configuration. </Speculation>

hiredman21:08:34

I have this really wild guess that in this case it might be due the library having native code for osx x86, and trying to load that into the process of a apple silicon native jvm, but that is way out over my skis (not a lot of evidence, and some of the evidence may contradict that)

1
seancorfield21:08:55

@U03DKTAF52P Is yours an M1 Mac or an x86 Mac?

loganrios21:08:02

M1 on my end. However, I would note that the same REPL load and functional call worked before I interrupted the CIDER REPL load, so it would be weird to me if it was an architecture issue, but that is also far out of my wheelhouse.

hiredman21:08:33

if can get the error to happen when using a repl start with clj, that is likely the easiest path to getting a good stacktrace

seancorfield21:08:27

(FWIW, I always start my REPL manually and just connect my editor to it -- because my REPLs tend to be longer-lived than my editor sessions)

๐Ÿ‘ 1
loganrios21:08:52

Wow, bizarre--the first library I can see in here appears to be Figwheel?

loganrios21:08:18

(if there's a prettier way to print this, feel free to let me know ๐Ÿ˜… )

seancorfield21:08:34

It's better to share actual text -- you can format

code with triple backticks
in Slack. But that just says that Figwheel failed to started due to the jna class loader error.

๐Ÿ‘ 1
hiredman21:08:55

hawk is, if I recall, a file watching library, and I bet that uses native code for monitoring the fileystem for changes

seancorfield21:08:59

Based on that stacktrace, it looks like Hawk is the probelm

hiredman21:08:03

so that makes sense

seancorfield21:08:36

Yeah, I bet it either doesn't have an M1 version or you need a more up to date version that the project currently has (via Figwheel Sidecar)

loganrios21:08:17

Ah. I'll see if bumping the Figwheel dependency up a few versions helps, but that pretty much answers my short-term question. Thanks so much for your help!!

hiredman21:08:38

well the barbarysoftware thing that hawk uses on osx seems unlikely to get an update https://github.com/gjoseph/BarbaryWatchService

loganrios21:08:56

For future reference--from a fresh install on another M1 Mac, everything seems to work out-of-the-box; both Hawk and Figwheel are behaving correctly. Not sure what I could've done to my existing setup to have borked it (or exactly what I can do to fix it).

seancorfield21:08:28

Did updating the version(s) of Figwheel and Sidecar help at all?

loganrios21:08:02

Unfortunately not ๐Ÿ˜•...

hiredman21:08:53

have you compared the jvm version on the two macs?

loganrios21:08:52

18.0.2 on the broken one, and 18.0.1 on the working one. I'll upgrade the working one and see if it breaks.

loganrios21:08:41

Confirmed that it works OOTB on 18.0.2 as well. Something must be really messed up on my other machine.

hiredman21:08:55

besides the version number, are they the same? like maybe the working one is using an x86 jvm above the emulation layer and the broken one is using a native apple silicon jvm

loganrios21:08:49

java -version outputs the following for both:

openjdk version "18.0.2" 2022-07-19
OpenJDK Runtime Environment Homebrew (build 18.0.2+0)
OpenJDK 64-Bit Server VM Homebrew (build 18.0.2+0, mixed mode, sharing)

hiredman21:08:29

not super useful I guess, but if you are getting it from homebrew it seems like they should be the same

hiredman21:08:48

(no native architecture stuff in the -version output of java)

loganrios21:08:39

Hmm. I'll keep digging--at the end of the day, maybe I just need to factory reset my whole machine. Really not sure how this happened.

hiredman20:08:16

clojure isn't doing it

hiredman20:08:21

some library you are using is

seancorfield20:08:04

๐Ÿงต(reminder)

hiredman20:08:13

what is happening is that library uses some native code, so it has something like a static method that writes the native code out to disk in the tmp file (see jna in the tmp file name) and then tries to link the native code in to the jvm process

Stuart21:08:24

Is their a function that takes a function and the number of times to call it? On each step it passes the output of the previous run, e.g.

(do-i-exist f 4 foo) 
Would do (f (f (f (f foo))) ? Right now I'm doing this:
(defn rotate-90ยฐ-n-times [n board]
  ((apply comp (take n (repeat rotate-90ยฐ-clockwise))) board))
But I'm thinking I'm probably missing something

seancorfield21:08:59

iterate and nth sounds like what you're looking for?

pppaul21:08:36

((comp f f f f f f f) foo) if you want to rewrite your first example

seancorfield21:08:13

user=> (take 4 (iterate inc 0))
(0 1 2 3)
user=> (nth (iterate inc 0) 2)
2
user=> (nth (iterate inc 42) 4)
46
user=>

Stuart21:08:40

Thanks sean, that's better!

seancorfield21:08:13

BTW, you can do (repeat n rotate...) to get n of that function.

seancorfield21:08:44

(so you don't need take in what you're doing now)

๐Ÿ‘ 1
pppaul21:08:27

interesting use of repeat

seancorfield21:08:32

user=> (doc repeat)
-------------------------
clojure.core/repeat
([x] [n x])
  Returns a lazy (infinite!, or length n if supplied) sequence of xs.
nil
user=>

Daniel Slutsky22:08:54

How many people here are new to Clojure and would find it useful to have an Intro to Clojure session as a preparation for the https://scicloj.github.io/docs/community/groups/ds4clj/ course?

Daniel Slutsky22:08:37

It'd be helpful to comment in this thread. ๐Ÿ™

Ben Lieberman01:08:24

me! is there some kind of registration for ds4clj?

Daniel Slutsky05:08:21

Wonderful ๐Ÿ™ There is no registration yet.