Fork me on GitHub
#clojure
<
2022-08-01
>
lvh00:08:30

What are the specific requirements for git libs to work in deps.edn? I am trying to use a package (nfs4j) that works fine via Maven coordinates but doesn’t via gitlib, and I have no idea how to debug:

❯ clj -Srepro -Sdeps '{:deps {org.dcache/nfs4j-core {:git/url "" :git/sha "23aaab51822633fcbc35e9d79b23ce40c64441b9"}}}' -e "(import org.dcache.nfs.vfs.VirtualFileSystem)"
WARNING: Implicit use of clojure.main with options is deprecated, use -M
Execution error (ClassNotFoundException) at java.net.URLClassLoader/findClass (URLClassLoader.java:445).
org.dcache.nfs.vfs.VirtualFileSystem

lvh00:08:29

(if you’re wondering why I care: its because that package is not hosted on maven central, and I don’t know how to restrict specific deps to a specific mvn repo, and I don’t love that some random third party repo can just hijack any dependency it likes)

lvh00:08:08

FWIW I checked in gitlibs and the checkout seems to have worked fine

Alex Miller (Clojure team)00:08:43

You can set GITLIBS_DEBUG=true to see the git commands. Once it's on disk, it's just pulling in the :paths per deps.edn

Alex Miller (Clojure team)00:08:55

clj -Spath will show you the classpath it's using in both cases

lvh00:08:11

cool, thanks!

lvh00:08:15

I think the thing I need may be :deps/prep-lib

lvh00:08:24

but we’ll see 😄

Alex Miller (Clojure team)00:08:45

Possibly if it relies on compiled classes

Alex Miller (Clojure team)00:08:05

But that lib would need to have instructions to prep in its deps.edn

lvh00:08:30

FWIW, the library in question is pure java

lvh00:08:08

maybe that’s just not expected to work at all and git libs are strictly for clojure libs?

dpsutton00:08:20

is it possible for you to get a jar by other means? curl it from some download page? Then you could just add a :deps/local path to the jar itself.

dpsutton00:08:28

gitlibs are more intended for clojure libs and has a way to prep libs but that requires the project to declare how to prep itself. No pure java lib will do this

Alex Miller (Clojure team)00:08:28

Yeah, this is not expected to work. Gitlibs are for Clojure source libs

lvh01:08:02

gotcha, thanks! I’ll do the “jar via other means” bit, thanks for the suggestion @U11BV7MTK 🙂

👍 1
Al Z. Heymer11:08:50

Oh? It is possible to do -e with unquoted classes? I always thought that needed to be quoted due to interpreter stuff.

Alex Miller (Clojure team)11:08:42

That's really a question about import, which works with either quoted or unquoted class symbols

didibus02:08:56

What's everyone's feeling about using tap> in libraries? Do anyone expect that nothing will ever tap> except for their own code?

Alex Miller (Clojure team)02:08:04

Generally should be added and removed for debugging

seancorfield02:08:05

I wouldn't intentionally commit code containing tap> for an OSS library. I've occasionally done that at work but it was a mistake. We still have a couple of tap> calls in our production code but we probably meant to remove them before deployment.

didibus02:08:54

So maybe if there's a way to turn it on or off. Let's say someone wants to offer tracing in their lib as a feature, you can go the log route, but that makes more assumptions or pulls in additional dependencies.

seancorfield02:08:51

tap> isn't "reliable" as a logging tool... debug-level tracing maybe... but that shouldn't be a concern for your users

didibus03:08:14

I feel its reliable enough for the use-case.

didibus03:08:17

> tap is a shared, globally accessible system for distributing a series of informational or diagnostic values to a set of (presumably effectful) handler functions. It can be used as a better debug prn, or for facilities like logging etc.

didibus03:08:00

So if a lib wants to offer diagnostic features, or informational events, would it not be a good fit?

hiredman03:08:03

It is a shared bus, there is no way to subscribe to only a subset of what is published

hiredman03:08:08

The docs for tools like portal set things up to unconditionally inspect values that get sent to tap

didibus03:08:46

Ya, but that still seems fine to me, the use-case is diagnostic features, or informational events its not part of the main behavior, its all cross-cutting to what the lib does.

didibus03:08:49

So it seems you would want to have it be an opt-in, but if you were interested in diagnostics or informational events about the behavior of a lib, you could turn tapping on for the lib

didibus03:08:32

I see next.jdbc did something different: https://github.com/seancorfield/next-jdbc/blob/7d5ee09e793720ed4f650dbc3762a3130f030296/doc/getting-started.md#logging This is what I was thinking at first, provide some ad-hoc way to give a callback to the lib

didibus03:08:49

But I figured, what's that for anyways, isn't this like what it is meant for.

didibus03:08:06

Or its really just a println meant for graphical tools.

seancorfield03:08:02

The main issue is that tap> has a buffer behind it that drops items when it is full. So when things are busy, you'll just lose data.

didibus05:08:43

Which is good so that you don't get paged accidentally in prod because someone forgot to disable the library debug and caused your whole service to brownout 😛

didibus05:08:58

If you needed to log for compliance, or actual user behavior, I would not rely on it, but this diagnostic use case seem apt to it I feel.

seancorfield05:08:47

We have two-level logging in production already. Well, three if you include New Relic. It's actually been amazingly productive to have WARN+ go to New Relic, a console log that is ERROR+, and a full, rolling log that is DEBUG+.

seancorfield05:08:32

(tbh, the E+ console log is the least valuable but still provides a good basis for automated "alerting" via scripts that scan log files)

didibus06:08:56

I just remember one issue where a library we were using was logging a ridiculous amount of debug data, and it slowed everything down as logging became a bottleneck. I guess nobody has realized the library was going to start logging stuff. You don't normally assume that.

borkdude07:08:36

You can configure clj-kondo with :discouraged-var to track tap> usage before you commit anything in an OSS lib

💯 1
Martynas Maciulevičius15:08:18

Hey. I used two slashes in a keyword and it worked on JVM Clojure. But now I installed a linter and it complains because it fails later in the data structure as it incorrectly parses things. So should keywords with more than one slash be used or not? borkdude showed that it's not allowed in CLJS but in babashka I can use keywords with two slashes. And in JVM I can use both - symbols and keywords with multiple slashes. Why is it different everywhere? Why not either deny this everywhere or allow everywhere? I used this for multiple months now without any issues on JVM and it worked just as I expected it to work -- name part contains the second slash.

Alex Miller (Clojure team)15:08:16

https://clojure.org/reference/reader - "'/' has special meaning, it can be used once in the middle of a symbol to separate the namespace from the name, e.g. my-namespace/foo. '/' by itself names the division function." (keywords are "like symbols")

Alex Miller (Clojure team)15:08:51

for best future compatibility, you should not use multiple slashes in keyword names

Martynas Maciulevičius15:08:09

Thanks. I'll try to add this chat into my issue of Clojure LSP so that they would add it into message. https://github.com/clojure-lsp/clojure-lsp/issues/1163

sheluchin15:08:15

https://clojure.org/reference/transducers#_sequence > These sequences will consume input incrementally as needed and fully realize intermediate operations. This behavior differs from the equivalent operations on lazy sequences. Could someone please explain the difference?

Alex Miller (Clojure team)15:08:41

things like mapcat and sequences are truly lazy - an intermediate step might produce an infinite number of values and that's ok

Alex Miller (Clojure team)15:08:27

with transducer mapcat, an infinite intermediate sequence is fully consumed (via internal reduce) and this would hang

sheluchin15:08:48

So producing a sequence with sequence will not do any chunking and will perform all of the xf + f over coll immediately?

Alex Miller (Clojure team)15:08:16

chunking is irrelevant here

Alex Miller (Clojure team)15:08:32

transducers is a push model, sequences is a pull model

1
Alex Miller (Clojure team)15:08:47

sequences "pull" as needed so can deal with lazy intermediate results

Alex Miller (Clojure team)15:08:24

transducers "push" the input values into the transducer stack. if it produces an infinite output, you have no way to just get some of it

sheluchin16:08:12

When using the sequence function to create a sequence from the application of a transducer to a collection, is this resulting in both a push and a pull, since there is a sequence and transducers involved? I think I'm getting a little tripped up because the term "sequence" is overloaded?

Alex Miller (Clojure team)16:08:55

it's a pull interface over a push transducer

Alex Miller (Clojure team)16:08:55

this is a subtle difference, and in many cases a non-difference. it mostly matters when an operation is an expander (can produce multiple outputs for one input value) like cat, mapcat

sheluchin22:08:52

Thanks @U064X3EF3. It's a little mind bending right now but I'll give it more thought and it'll sink in more over time. The push vs. pull comparison is going to give me something to think about.

hiredman17:08:22

has it stopped building yet?

diego.videco17:08:36

Sorry, wrong slack 🥴

Jacob Emcken19:08:37

I'm trying to understand protocols in Clojure and was reading the example given on https://clojure.org/reference/protocols#_basics:

(defprotocol P
  (foo [x])
  (bar-me [x] [x y]))

(deftype Foo [a b c]
  P
  (foo [x] a)
  (bar-me [x] b)
  (bar-me [x y] (+ c y)))

(println (bar-me (Foo. 1 2 3) 42))
I added a println on the last line to allow easy feedback when running it in http://replit.com Now I tried to move the protocol into a different namespace like so:
(ns proto)

(defprotocol P
  (foo [x])
  (bar-me [x] [x y]))

(ns main
  (:require [proto]))

(deftype Foo [a b c]
  proto/P
  (foo [x] a)
  (bar-me [x] b)
  (bar-me [x y] (+ c y)))

(println (bar-me (Foo. 1 2 3) 42))
Causing Unable to resolve symbol: bar-me in this context I am missing something... but I do not understand what.

Alex Miller (Clojure team)19:08:14

the protocol functions "live" in the namespace where they are defined with defprotocol

Alex Miller (Clojure team)19:08:32

so in the last line, bar-me should be proto/bar-me

Alex Miller (Clojure team)20:08:41

(and this is an important bit of abstraction - calling a protocol function and a non-protocol function look the same from the invoker's point of view)

Jacob Emcken20:08:19

I didn't get what x was in the example, but it is what is sometimes also referred as this ?

Jacob Emcken20:08:16

so x is actually an instance of Foo

Jacob Emcken20:08:24

Thanks a lot, it was really helpful for me

Alex Miller (Clojure team)20:08:12

I think we actually have a web site issue to make this example suck less :)

🙌 2
kingcode21:08:40

I am trying to create an editing prompt at the repl to have the user edit an existing value: the user is prompted with the value and and can backspace and edit at will before pressing ‘Enter’ to have the value read, kind of as read-line does. What is the best way to do this? I imagine some kind of pushback reader…thanks for any comment.

hiredman21:08:38

line editing like that is somewhat complex

hiredman21:08:18

I guess you just mean reading a line at a time, which should be fine with just using read-line

kingcode21:08:57

@hiredman, Yes, a single line at a time: print a value with the cursor positioned at the end: the user can edit at will, and press Enter

hiredman21:08:19

oh, no, you'll need the complex line editing for that

kingcode21:08:23

Only, read-line doesn’t do any editing

kingcode21:08:38

ah ok… any lib around?

hiredman21:08:38

interacting with the tty not with the stdin and out streams

kingcode21:08:24

I would be fine with backspace characters appended to the initial string, as long as the user can ‘edit’ over it.

hiredman21:08:47

JReadline maybe

hiredman21:08:12

that will only work if the repl is running in a real terminal, but a repl can in theory be running on any input and output streams

hiredman21:08:46

and the in and out of a repl don't always match the stdin and stdout of the process running the repl

seancorfield21:08:37

Threads, please! Don't clog up the entire main channel for a single conversation!

hiredman22:08:53

there hadn't been another message in the channel for over an hour, is it clogged?

kingcode22:08:41

how do I create a thread?

seancorfield22:08:55

If you don't use threads, some people are going to get notified on every message in the channel -- and it also means earlier questions get scrolled off the screen and more likely to get lost in the "noise".

seancorfield22:08:30

@U06BUCH6D when you mouse over a message, Slack shows a speech balloon icon for reply in thread.

hiredman22:08:04

slack has a pretty comprehensive set of preferences for notifications that a user can tune for themself

seancorfield22:08:32

Folks answering questions should use threads by default in the main channels like #beginners and #clojure -- if you're in a smaller channel, it's fine to chat directly in the channel.

seancorfield22:08:03

Many people here have asked us (the admin team) to encourage the use of threads in large channels. Please respect those people's wishes.

hiredman22:08:30

again, there hadn't been another message in the channel for an hour, it is hardly noisy

kingcode22:08:32

Got it! 🙂

kingcode22:08:18

Anyway, to get back to my question, it looks like an interesting problem: print the string to be edited by the user and grab the edit with read-line or something similar.

kingcode22:08:06

If there was a way to ‘populate’ the background with chars from the editable value. Sorry, not familiar with tty vs *in* and *out* streams

hiredman22:08:18

it isn't possible

hiredman22:08:55

line editing is a feature of the terminal, in and out streams are just conveyors of bytes

kingcode22:08:22

I see….that makes sense. Thanks for your advice!

richiardiandrea22:08:46

Hi there, I would like for my backend to return the fields that did not validate against spec. Is there a library that extracts that in the wild by any chance? I know this is not properly a good pattern in spec1 and I'd be willing to try other alternatives in case... Thanks in advance!

richiardiandrea22:08:03

thank you, I can definitely write custom parsing code but I'd rather go for a library, if anything is available

hiredman22:08:08

the thing to keep in mind is a spec describes a tree, so the failure result isn't just a list of failed keys, it has to account for and be able to explain failures at different locations in the tree

richiardiandrea22:08:35

something like this is what I am playing with right now https://github.com/metosin/malli#error-messages

hiredman22:08:49

not sure what you mean by parsing? explain-data returns a data structure

richiardiandrea22:08:10

yes I'd have to parse that data structure and extract the fields that are failing

richiardiandrea22:08:43

in this example for instance

{:problems
                     ({:path [],
                       :pred
                       (clojure.core/fn
                        [%]
                        (clojure.core/or
                         (clojure.core/contains? % :dosage)
                         (clojure.core/contains? % :volume))),
                       :val {:foo :bar},
                       :via
                       [:contrast-agent/updatable-model],
                       :in []}),
                     :spec :acontrast-agent/updatable-model,
                     :value {:foo :bar}}
I'd have to get to the contains? form

richiardiandrea22:08:17

doable, but I am wondering if there is anything out there that does that for me 😄

richiardiandrea22:08:10

and I think I have got (somehow) a winner 😄 https://github.com/athos/spectrace

richiardiandrea23:08:05

Ah, tried and it does not seem to work against the above use case, where an empty map is missing some required keys

hiredman23:08:56

if you predicates are opaque functions like :pred above, then it is going to be difficult to get anything reliably

hiredman23:08:06

the reason spec's combinators exist for building specs, instead of just making new predicate functions, is specs expose their structure for things like reporting and generative testing

richiardiandrea15:08:26

Ok thanks...in a way I just need to know which field is failing the predicate, I was experimenting with malli yesterday and it seems to fit the bill...