clojure

New to Clojure? Try the #beginners channel. Official docs: https://clojure.org/ Searchable message archives: https://clojurians-log.clojureverse.org/
pez 2021-03-17T08:46:50.004400Z

So this was what you helped me with, yesterday, @dpsutton and @seancorfield https://github.com/PEZ/taplet I notice that the tests are not as predictable as I would expect them to be. It sometimes seem like they write over each other’s atoms, but since they are locals that really can’t be happening. Anyway, I don’t understand why the tests get brittle. Not planning to put this in CI, though, so it is OK for now. Anyway, I have a bunch of questions about macros now, so will probably return here. Thanks again for the super duper support!

2021-03-17T11:01:57.006Z

Hello. #vscode channel looks like forgotten, so sorry for asking here - is there any usable Clojure code formatter for VSCode?

dharrigan 2021-03-17T11:02:28.006200Z

Try #calva

dharrigan 2021-03-17T11:03:24.007400Z

Oh, I see you've already asked there.

dharrigan 2021-03-17T11:03:35.007800Z

Can't help sorry, not a vscode user.

2021-03-17T11:04:09.008500Z

Thanks, I used it several years before it becames unusable due to unswitchible lsp integration. Now I installed Clover, clj-condo linter and only one thing I need is formatter.

2021-03-17T11:27:23.009900Z

Hey folks, got a question for people who know there way around Java interop

2021-03-17T11:28:01.010800Z

I am using openhft Java runtime compiler to compile Java classes dynamically

2021-03-17T11:28:27.011400Z

Im getting to the compiling part just fine

2021-03-17T11:28:52.012200Z

But the class file contains Java interfaces and other class definitions etc

2021-03-17T11:29:35.013500Z

Now I’m wondering how I can load these files and symbols from the Java project into my clojure namespace to make it accessible to the compiler

2021-03-17T11:29:52.014100Z

I guess I need to put them on the classpath somehow?

ericdallo 2021-03-17T11:32:56.014200Z

Just to be curious, what issues you had with Calva LSP(clojure-lsp)? Maybe we can improve that

pez 2021-03-17T11:51:44.014900Z

I think hacking Calva-fmt to accept your config is a way to do it.

✅ 1
borkdude 2021-03-17T11:52:08.015500Z

@dev-hartmann a convention in some clojure projects is to have a directory classes where you emit these classes and then put classes in your :paths in deps.edn. For lein this directory is called target and it is on the classpath by default

🤘 1
2021-03-17T11:54:30.015900Z

Thanks, I'l try this way.

2021-03-17T12:07:49.017700Z

Thx @borkdude I guess I can get maven to export the classes from the other project and cp them into a classes folder in my clojure project

borkdude 2021-03-17T12:08:29.018Z

or just add the other path to your :paths

borkdude 2021-03-17T12:08:54.018300Z

:local/root + adding deps.edn in that project might also work, if the path is not within the project

2021-03-17T12:11:09.018800Z

Ah, interesting I’ll try

2021-03-17T12:13:25.019200Z

The other project is a pure Java project

2021-03-17T12:13:56.020100Z

I‘ll try adding it to my paths in deps.edn and maybe it works then 😎

borkdude 2021-03-17T12:15:17.020800Z

@dev-hartmann if the other project has a pom.xml and the classes are on the classpath of that pom.xml, then you can use :local/root to add that project

2021-03-17T12:15:44.021200Z

Yes it has a pom.xml

2021-03-17T12:16:12.022100Z

Nice, I’ll read up on :local/root, thank you very much

2021-03-17T12:17:04.022300Z

Ah got it

2021-03-17T12:17:26.023100Z

I can import the complete project as a dependency but specifiying it is local 👌:skin-tone-4:

2021-03-17T12:17:33.023300Z

That’s awesome

2021-03-17T12:29:40.023600Z

Wow, seems to work

2021-03-17T12:29:44.023800Z

🤯

2021-03-17T12:31:47.025100Z

Now I just need to add the company private nexus to use everything

2021-03-17T12:32:09.025900Z

That’s just brilliant, thx a lot @borkdude !

borkdude 2021-03-17T12:38:52.026200Z

Sure. Join #tools-deps if you have any other questions about this

2021-03-17T12:47:52.026500Z

Thx, will do 👍:skin-tone-4:

restenb 2021-03-17T15:34:52.027900Z

what would be a good way to block a thread until a channel (or atom) holds a specific value?

restenb 2021-03-17T15:36:38.029Z

invert the problem, only put expected value on the channel and just use <!! ?

alexmiller 2021-03-17T15:37:09.029700Z

put a filter transducer on the channel and just take

👍 2
2021-03-17T16:01:25.030400Z

you can use a watch on an atom

2021-03-17T16:05:00.033Z

(defn when-is [a v] (let [k (Object.) p (promise)] (add-watch a (fn [a k ov nv] (when (= nv v) (deliver p true) (remove-watch a k)))) (when (= @a v) (deliver p true) (remove-watch a k)) @p)) ;; the order of args to the watch fn is likely wrong

2021-03-17T16:05:28.033300Z

and I forgot to deref the promise

2021-03-17T16:08:13.033500Z

regarding the add-watch argument order, I've found kron to be helpful as a mnemonic (Key/Ref/Old/New)

Eugen 2021-03-17T16:32:05.035300Z

Java 16 is out and I presume it works with Clojure. I know it brings strong encapsulation by default, so my question is: How does this impact Clojure ? https://jdk.java.net/16/release-notes

alexmiller 2021-03-17T16:32:24.035600Z

It does work with Clojure

alexmiller 2021-03-17T16:32:40.036Z

Does not really impact Clojure much

👍 1
2021-03-17T16:34:28.036100Z

Which part of the article you linked describes the part you mention as "string encapsulation"? Are you referring to the part of the linked document titled "Improve Encoding of TLS Application-Layer Protocol Negotiation (ALPN) Values" ?

Eugen 2021-03-17T16:34:55.036300Z

Strong* - typo, sorry

Eugen 2021-03-17T16:35:32.036600Z

JEP 396: Strongly Encapsulate JDK Internals by Default (JDK-8256299)
core-libs

Strongly encapsulate all internal elements of the JDK by default, except for critical internal APIs such as sun.misc.Unsafe. Allow end users to choose the relaxed strong encapsulation that has been the default since JDK 9.

With this change, the default value of the launcher option --illegal-access is now deny rather than permit. As a consequence, existing code that uses most internal classes, methods, or fields of the JDK will fail to run. Such code can be made to run on JDK 16 by specifying --illegal-access=permit. That option will, however, be removed in a future release.

For further details, please see JEP 396.

2021-03-17T16:36:48.036900Z

I haven't tried, but wonder if this is a release where some things that were warnings in previous JDKs become errors, that might affect a few libraries here and there that issued warnings with earlier JDKs.

2021-03-17T16:37:48.037300Z

no fancy compiler stuff related to record classes?

2021-03-17T16:37:50.037400Z

Even if so, that issue is not Clojure-specific, I believe -- just that certain JVM code will need explicit permissions that they didn't need before.

👍 1
ghadi 2021-03-17T16:41:22.038100Z

records are useful for java devs but boooring for Clojure devs

ghadi 2021-03-17T16:41:56.038800Z

we already have boilerplate-free, immutable, transparent state carriers: maps

ghadi 2021-03-17T16:42:42.039700Z

I do not care about the language level stuff in JDK 16, but the VM level stuff is absolutely massive

ghadi 2021-03-17T16:43:25.040500Z

high-level SIMD API (Vector API, incubating) call C functions directly without writing a lick of JNI (Foreign Linker API, incubating)

2021-03-17T16:43:56.040900Z

sure, I was thinking more in terms of how the Clojure compiler/runtime works, not so much the API layer, but I don’t know nearly enough about how Clojure is implemented to know whether something like, say, pattern matching of records, can provide any value (ex: like for optimizing cond or something)

borkdude 2021-03-17T16:44:02.041300Z

> call C functions directly without writing a lick of JNI does this bring a Python-like FFI for C libs for Clojure a bit closer?

ghadi 2021-03-17T16:44:15.041600Z

yeah, stay tuned, I'm cooking up something nice

borkdude 2021-03-17T16:44:44.042200Z

niiice :) hope it works with GraalVM as well, can add it to bb and have more lib reach :)

ghadi 2021-03-17T16:44:54.042500Z

it won't 🙂

2021-03-17T16:45:06.043100Z

graalvm is java11 based tops

borkdude 2021-03-17T16:45:33.043800Z

GraalVM will update to 16 /17 eventually, but are there any technical reasons it shouldn't work?

borkdude 2021-03-17T16:49:52.044300Z

I'm assuming you're doing something byte-code emitting related right?

ghadi 2021-03-17T16:51:01.045400Z

yeah right now I’m spinning dynamic IFn -> MethodHandle proxies

Eugen 2021-03-17T16:51:04.045500Z

I think it will happen with 17 - the next LTS

ghadi 2021-03-17T16:51:35.046600Z

Could have other impls possible

ghadi 2021-03-17T17:00:23.048300Z

ZGC max pause times from 10ms -> 1ms is very exciting too (heap size agnostic!)

seancorfield 2021-03-17T17:09:49.051100Z

TIL re: Java 16 — public constructors for the primitive wrapper classes (`Long`, Double, Integer, etc) have been deprecated since Java 9 (searches all his code, finds no such uses 😅 ).

🙂 3
dpsutton 2021-03-17T17:11:21.051400Z

do you mean they have been removed finally?

seancorfield 2021-03-17T17:12:48.052200Z

Not yet, but in Java 16 you’ll get warnings on their usage. And they will go away eventually. I’d just totally missed they’d been deprecated for so long!

dpsutton 2021-03-17T17:14:24.053100Z

oh i didn't realize 16 started emitting warnings about them. i knew they were deprecated for a while

alexmiller 2021-03-17T17:23:23.054300Z

I think they've been linting that for years if you check deprecation warnings

alexmiller 2021-03-17T17:25:24.054700Z

pretty sure we did a pass through Clojure source 2-3 years ago to fix up a couple

borkdude 2021-03-17T17:28:10.055Z

but you won't see it through Clojure interop, right?

borkdude 2021-03-17T17:28:51.055300Z

(maybe clj-kondo can fix this)

alexmiller 2021-03-17T17:29:10.055600Z

oh, you mean if you used Clojure to invoke the Java constructor?

borkdude 2021-03-17T17:29:33.056100Z

yes

alexmiller 2021-03-17T17:29:43.056400Z

should be able to lint that, I don't think you'd see it otherwise

Huahai 2021-03-17T17:29:57.056600Z

\

borkdude 2021-03-17T17:30:12.057Z

you mean, should be able to lint that, who?

borkdude 2021-03-17T17:30:30.057400Z

java, clojure, clj-kondo?

alexmiller 2021-03-17T17:30:38.057700Z

clj-kondo

borkdude 2021-03-17T17:30:52.058300Z

ok, I'll add an issue for it

alexmiller 2021-03-17T17:32:25.059100Z

just grepping a few quick examples, surely there are more

borkdude 2021-03-17T17:32:44.059500Z

the clojure reflector already checks for "canAccess", is this something it could do too? or too much perf overhead / info not available in the JVM?

alexmiller 2021-03-17T17:34:24.060500Z

what I've found in the past is that canAccess will only give feedback when it's set to "deny", so it probably won't help until they actually turn it off

alexmiller 2021-03-17T17:35:29.061Z

I don't think we want to be in the business of checking for specific invocations inside the reflector

alexmiller 2021-03-17T17:37:28.061800Z

linting seems like the right level of check to me

borkdude 2021-03-17T17:39:46.062400Z

I agree about not adding specifics. Was just wondering if https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Constructor.html had a field "deprecated" or something, but it hasn't.

alexmiller 2021-03-17T17:45:32.062800Z

nah, I don't think there is any way to tell this programmatically

alexmiller 2021-03-17T17:45:58.063300Z

I mean I guess you could check for a Deprecated annotation on the method

borkdude 2021-03-17T17:46:54.063800Z

I'll probably use that to generate a list of deprecated methods for linting

alexmiller 2021-03-17T17:47:03.064100Z

https://download.java.net/java/early_access/jdk16/docs/api/java.base/java/lang/Boolean.html#%3Cinit%3E(boolean) - you can see that the info is there and I think that's retrievable

alexmiller 2021-03-17T17:47:41.064800Z

the annotation has to be marked to be marked for runtime retention but that one should be

alexmiller 2021-03-17T17:49:26.065400Z

so, I'll change my answer - yes, it's possible to programmatically detect this in the reflector :)

alexmiller 2021-03-17T17:49:49.065700Z

should we is a separate question :)

borkdude 2021-03-17T17:50:13.066Z

pushing things to lint-time is better for performance ;)

alexmiller 2021-03-17T17:50:46.066600Z

yeah, that would need assessment. I would not be opposed to an ask.clojure question about this, might generally be a useful thing, at least as an option

alexmiller 2021-03-17T17:51:41.067100Z

surprising that I do not remember anyone asking about this before now

2021-03-17T17:52:11.067300Z

You tend to be first on about 50% of things like this, I believe 🙂

borkdude 2021-03-17T17:52:17.067600Z

afaik clojure itself doesn't even warn about deprecated vars?

alexmiller 2021-03-17T17:59:19.067700Z

seems like a semi-obvious idea that has been available since Java 5, so basically forever in Clojure release lifetime

dpsutton 2021-03-17T18:03:58.069100Z

Oh does kondo not warn on this? Cider nrepl has done this for a while and it’s quite nice. I’m doing a month without nrepl and didn’t look into this yet

alexmiller 2021-03-17T18:10:22.069700Z

there definitely is a ticket about Clojure :)

alexmiller 2021-03-17T18:11:18.069900Z

https://clojure.atlassian.net/browse/CLJ-706

borkdude 2021-03-17T18:29:17.070900Z

@dpsutton yes, kondo warns, but clojure doesn't

vemv 2021-03-17T18:54:39.073100Z

I didn't expect that (binding [*read-eval* false] (load "some/ns")) would still execute a contained #=(println 42) I guess there's no built-in way to forbid read-eval literals in clojure namespaces?

dpsutton 2021-03-17T19:02:47.074100Z

oh what a weird thing: (var + nonsense) -> #'clojure.core/+

ghadi 2021-03-17T19:03:11.074600Z

warns on clojure deprecations or java deprecations or both?

dpsutton 2021-03-17T19:03:35.075200Z

and so threading last into a private function call at the repl is quite surprising at first. (->> foo #'ns/private-fn) yields ns/private-fn

borkdude 2021-03-17T19:06:30.075300Z

currently warns on deprecated vars. I just made an issue for deprecated methods/constructors, but it doesn't do that yet

dpsutton 2021-03-17T19:07:11.075500Z

i got a bit turned around on which deprecations i was thinking of 🙂

borkdude 2021-03-17T19:09:39.075800Z

Hmm:

user=> (binding [*read-eval* false] (read-string "#=(println :foo)"))
Execution error at user/eval138 (REPL:1).
EvalReader not allowed when *read-eval* is false.
user=> (binding [*read-eval* false] (load-string "#=(println :foo)"))
:foo
nil

👍 1
dpsutton 2021-03-17T19:14:16.076Z

if you're loading code, does it matter if there are the #= forms? it's executing everything right? you're trusting the source

alexmiller 2021-03-17T19:15:45.076200Z

this slightly pre-dates my involvement with Clojure core, but my recollection is that read-eval is there to prevent read eval when reading untrusted data with read. Code on your classpath (loaded by load) is presumably there because you put it there and it is considered to be trusted and thus outside the scope of read-eval

alexmiller 2021-03-17T19:16:54.076400Z

as dpsutton says, it's not just going to read, it's going to eval as well

vemv 2021-03-17T20:48:51.077100Z

@borkdude yeah precisely, it's that difference that I found surprising. TIL about load-string btw!

vemv 2021-03-17T20:50:34.077300Z

yeah that reasoning makes sense, in the end one is also evaling a string when doing load, require, etc. But the difference might be considered quirky. I ended up using tools.reader. It offers its own *read-eval* var; if binding it to false while content some contents one will get an exception, as I was seeking

alexmiller 2021-03-17T20:53:18.079Z

that should be the same as using clojure.core/read

alexmiller 2021-03-17T20:53:51.079200Z

don't know why you need tools.reader for that

vemv 2021-03-17T20:58:03.079400Z

you're right, it's not an essential part. In my project tools.reader is used for all reading needs though And [clojure.core/*read-eval* false] in combination with tools.reader does not result in errors being thrown, but in nil values being read

dpsutton 2021-03-17T21:07:59.079600Z

can i ask what problem you're trying to solve?

vemv 2021-03-17T21:10:58.079800Z

Linting against #=() syntax, I've seen it in production projects and as I saw it, it wasn't either a good thing or something without viable alternatives

borkdude 2021-03-17T21:12:36.080Z

Might be something we could add to clj-kondo as well

dpsutton 2021-03-17T21:12:47.080200Z

i was just wondering if grasp could identify them

borkdude 2021-03-17T21:12:48.080400Z

As in: when you enable the linter, warn

borkdude 2021-03-17T21:13:35.080600Z

This is easier with clj-kondo or let's say, just rewrite-clj for example. Grasp assumes that your code already has been parsed correctly

borkdude 2021-03-17T21:14:26.080800Z

Or in fact, I do think grasp will throw when it encounters one of those.

borkdude 2021-03-17T21:14:41.081Z

Similar to how bb throws:

$ bb -e '#=(+ 1 2 3)'

----- Context ------------------------------------------------------------------
1: #=(+ 1 2 3)
    ^--- Read-eval not allowed. Use the `:read-eval` option

borkdude 2021-03-17T21:15:36.081300Z

You can also parse all your code with edamame (which is one level below grasp / sci)

borkdude 2021-03-17T21:15:39.081500Z

to do the same

borkdude 2021-03-17T21:15:49.081700Z

it's built on top of tools.reader

richiardiandrea 2021-03-17T23:52:51.085400Z

Hi all, I am having a strange issue with spec instrumentation that throws where it should not... What is peculiar is that the instrumentation exception show this :via (notice the repetition):

[::report/report-identifiers
 ::report/report-identifiers
 ::report/image-descriptors
 ::report/image-descriptor
 ::report/image-id]
But my ::report/report-identifiers looks like
(s/def ::report-identifiers
  (s/keys :req [::id
                ::version-id]))
I am having trouble even debugging it...cause the registry seems to return the above spec definition but the instrumentation check then fails...do you folks have any hint?