Fork me on GitHub
#clojure
<
2024-02-09
>
Kira Howe03:02:16

Is it possible to somehow pass a nice error message to print when using :pre to test function inputs? (the context is a library where I would like to print something friendly/easily interpretable when invalid inputs are given).. is :pre even the best way to do that? It just seemed preferable to a big cond of input validations that throw errors with my custom messages.

Bob B04:02:35

disclaimer: this is mostly guesswork/conjecture I vaguely remember fogus talking about a library he wrote called trammel that did contracts with messages. Going back to look at it again, it looks like at least some of the stuff from trammel got ported into <https://github.com/clojure/core.contracts>, but that is marked as inactive and having been superceded by spec. To that end, maybe a possibility would be to have specs validate the input and throw a custom message if the spec isn't met. It might not be quite as concise as some of the core.contracts API, but maybe nicer to work with than the big cond.

❤️ 1
p-himik08:02:30

Yeah, I'd definitely go with some schema library. Nowadays I prefer Malli.

❤️ 1
vemv09:02:55

This is nice:

{:pre  [(s/assert number? foo)]
 :post [(s/assert string? %)]}
....Of course there are many other approaches, but what I specifically like is: • it's an easy-to-learn, gateway drug for teams without introducing syntax • doesn't use function instrumentation - personally I've never liked it as it can easily break depending on how tools interact, code is reloaded, etc (there's also Malli validate )

❤️ 1
p-himik09:02:38

If it's a contract check, I myself would definitely stray away from asserts of any kind. Clojure's asserts can be disabled (and those are used by :pre and :post), Spec's asserts can also be disabled, and in two separate ways. In my code, I prefer using a custom defn macro that wraps the fn body with checks based on a given input/output schema. Exactly like :pre and :post work.

1
vemv09:02:38

It's a couple props away

"-Dclojure.spec.compile-asserts=true"
"-Dclojure.spec.check-asserts=true"
Having authored one of those macros (https://github.com/nedap/speced.def), I'm fine with both approaches. But most times it's more effective to start with the gateway drug ^^

mpenet10:02:53

you can throw https://github.com/exoscale/lingo on top for nicer error messages

mpenet10:02:57

or expound

Kira Howe14:02:35

I think it’s ok for asserts to be disable-able.. if someone doesn’t want helpful error messages they could choose to turn them off. I was thinking of spec/malli but I was leaning toward minimizing the dependencies, but it’s worth looking into some more.

Kira Howe14:02:55

A custom macro/solution is probably what most people end up doing.. this is great, though, thanks for the suggestions.

Kira Howe14:02:16

@U45T93RA6 I like the pre/`post` stuff, but the errors it throws are not very user-friendly (e.g. Assert failed: ..some code..) . I would rather print something like Assert failed: Column name is invalid , I was wondering if it’s possible to somehow pass a custom error message for the pre assert to print..

vemv14:02:15

Normally the s/assert within :pre is clear enough (it's not vanilla :pre) Column name is invalid might read nice at the first time, but 1000 times later one typically just wants the info - no distractions 🙂 But yes, a higher-level lib will make an effort at producing a nice message. I mentioned mine. https://github.com/fulcrologic/guardrails got a release yesterday

vemv14:02:32

Also, good spec naming helps: ::age vs. number?

Kira Howe14:02:07

it depends who the audience is.. for context I’m working on libraries for data people who might not be familiar with software or programming in general.. if they see, for example, AssertionError: (set/subset? columns #{col1 col2}) , it might not mean anything at all to them, but spelling out “Invalid column name” would be helpful.

vemv14:02:57

{:pre [(s/assert (s/coll-of ::valid-column-name) column-names)]}
might produce a reasonably self-describing report It's not only that I used a name, but also Spec in a specific manner (coll-of vs. an arbitrary predicate) Using spec in idiomatic ways translates to nicer reports that misc tooling can understand

Kira Howe14:02:19

guardrails looks really cool.. cryptic error messages are consistently one of the most-complained about things in Clojure, and whilst I totally agree to most software engineers it doesn’t matter and is a low priority, I think it’s also important to also keep in mind users of our software who might not be software people

Kira Howe14:02:38

that makes sense.. this is super helpful, thank you!

vemv14:02:13

Worth noting, :pre is a tool for programmers (or soon-to-be programmers :) ). Generally one would disable it in production If I wanted an error message to show up to end users, I wouldn't use :pre or function instrumentation. I'd use something more explicit that ran in all environments, no matter what. Anyway, I know nothing about the use case and am sure that you can keep exploring the alternatives out there 🙌

p-himik14:02:17

> Generally one would disable it in production A heavily debatable topic, it turns out. :) https://clojurians.slack.com/archives/C03S1KBA2/p1707239220487469

vemv14:02:59

Honestly it isn't to me, Design by contract and assertions being disabled in production both predate Clojure Enabling assert in prod is essentially a blank cheque for third-party libraries to affect performance in arbitrary ways. (but yes, it's "debatable")

Kira Howe14:02:07

yeah that’s a good point.. I want these messages to show up for end users. but this also isn’t application code, it will be a tool for use in working with data that you’d use mostly at a repl

👍 1
seancorfield03:02:58

1.12.0-alpha7 -- tripped over the new Type* syntax in our code but the reflection warnings and error were non-obvious -- details in thread 🧵

seancorfield03:02:08

Reflection warning, ws/messaging/recognizer.clj:48:1 - reference to field count on [Lcompile__stub.ws.messaging.recognizer.Eps; can't be resolved.
Reflection warning, ws/messaging/recognizer.clj:48:1 - reference to field count on [Lcompile__stub.ws.messaging.recognizer.Eps; can't be resolved.
Reflection warning, ws/messaging/recognizer.clj:48:1 - call to method valAt on [Lcompile__stub.ws.messaging.recognizer.Eps; can't be resolved (no such method).
Reflection warning, ws/messaging/recognizer.clj:48:1 - call to method valAt on [Lcompile__stub.ws.messaging.recognizer.Eps; can't be resolved (no such method).
Reflection warning, ws/messaging/recognizer.clj:48:1 - call to method valAt on [Lcompile__stub.ws.messaging.recognizer.Eps; can't be resolved (no such method).
Syntax error (IllegalArgumentException) compiling new at (ws/messaging/recognizer.clj:48:1).
No matching ctor found for class [Lws.messaging.recognizer.Eps;

Alex Miller (Clojure team)03:02:43

can you give an example of the code? not sure I get it

seancorfield03:02:51

This is the source code (edited to remove clutter):

(ns ws.messaging.recognizer)

(set! *warn-on-reflection* true)

(declare empty-language?)

(defprotocol Language
  (parse-derive [lang input])
  (nullable? [lang])
  (parse-null [_])
  (parse-more? [_])
  (-compact [_]))

(defrecord Empty []
  Language
  (parse-derive [lang input]
    lang)
  (nullable? [_]
    false)
  (parse-null [_]
    #{})
  (-compact [this]
    this))

(defrecord Eps*[items] ;; this is line 48 in the original file
  Language
  (parse-derive [lang input]
    (->Empty))
  (nullable? [_]
    true)
  (parse-null [_]
    items)
  (-compact [this]
    this))

seancorfield03:02:15

And Eps* is now treated as an array type.

seancorfield03:02:16

(it's fine this broke -- I just renamed it to EpsItems throughout -- but the warnings/errors were... opaque)

Alex Miller (Clojure team)03:02:58

hmm, wasn't expecting that to break, so good catch

seancorfield03:02:35

If I just paste the defprotocol and two defrecord forms into the REPL, I get this rather unhelpful error:

Syntax error (ClassNotFoundException) compiling . at (REPL:1:1).
compile__stub.user.Eps

seancorfield03:02:24

(our full test suite is running now -- I'll start new threads if I trip over anything else)

seancorfield03:02:05

We use athos/clj-check to do a compile pass on all our code to flush out reflection warnings, which is where the original output comes from. LMK if you need any more info to repro.

Alex Miller (Clojure team)03:02:00

I logged it, we'll look at it

seancorfield06:02:29

An observation about 1.12.0-alpha7 and constructors: I sort of expected (some.Thing. x) and (some.Thing/new x) to be equivalent but they are not. The former will succeed when the latter will fail if there are multiple constructor overloads. Example: (java.sql.Date. (.getTime #inst "2024-02-08")) succeeds -- java.sql.Date has a constructor taking a long and a constructor taking three int values (year, month, day). (java.sql.Date/new (.getTime #inst "2024-02-08")) fails -- you need (^[long] java.sql.Date/new (.getTime #inst "2024-02-08")) to uniquely select a specific constructor. This is the second example I ran into: the first was java.net.URI (which has five constructor overloads, all different in arity).

seancorfield06:02:36

Per the news post which makes it obvious why this is the case (emphasis mine): "Given a fully resolved qualified method symbol, the compiler does no inference from target type, arg types or arity and reflection will not occur."

Alex Miller (Clojure team)10:02:55

Yes, these are intentionally not the same

Alex Miller (Clojure team)10:02:29

The qualified method syntax requires specificity, and does no inference, but also guarantees there is no reflection, except for the static method with no param tags case (which already existed and thus continues to do inference as before)

Leaf Garland06:02:22

I'm seeing a stack overflow when connecting to a Datomic pro transactor with clojure 1.12.0-alpha7 (and alpha6), but it works with alpha5. Possibly deref related. Details in thread.

Leaf Garland06:02:20

### start transactor
~/datomic-pro-1.0.7075
❯ bin/transactor config/samples/dev-transactor-template.properties
Launching with Java options -server -Xms1g -Xmx1g -XX:+UseG1GC -XX:MaxGCPauseMillis=50
System started

### create a new datomic:dev db
~/datomic-pro-1.0.7075
❯ bin/repl
Clojure 1.11.1
user=> (require '[datomic.api :as d])
nil
user=> (d/create-database "datomic:")
true

### connect with alpha5
~/datomic-pro-1.0.7075
❯ clj -Sdeps '{:deps {org.clojure/clojure {:mvn/version "1.12.0-alpha5"} com.datomic/peer {:mvn/version "1.0.7075"}}}}'
Clojure 1.12.0-alpha5
user=> (require '[datomic.api :as d])
nil
user=> (d/connect "datomic:")
#object[datomic.peer.Connection 0x2568611c "{:unsent-updates-queue 0, :pending-txes 0, :next-t 1000, :basis-t 66, :index-rev 0, :db-id \"test-db-12424771-a6e0-417f-9ac4-5b0669c3b485\"}"]

### connect with alpha7
~/datomic-pro-1.0.7075
❯ clj -Sdeps '{:deps {org.clojure/clojure {:mvn/version "1.12.0-alpha7"} com.datomic/peer {:mvn/version "1.0.7075"}}}}'
Clojure 1.12.0-alpha7
user=> (require '[datomic.api :as d])
nil
user=> (d/connect "datomic:")
Execution error (StackOverflowError) at datomic.promise$settable_future$reify__12002/get (promise.clj:45).
null
user=> *e
#error {
 :cause nil
 :via
 [{:type clojure.lang.ExceptionInfo
   :message "Error communicating with HOST localhost on PORT 4334"
   :data {:alt-host nil, :peer-version 2, :password "<redacted>", :username "UdJkV7ZVcVfXV0Ik/bVWgX4dbAXHe+LVq2qGyY1RBBc=", :port 4334, :host "localhost", :version "1.0.7075", :timestamp 1707454066998, :encrypt-channel true}
   :at [datomic.connector$endpoint_error invokeStatic "connector.clj" 53]}
  {:type java.lang.StackOverflowError
   :message nil
   :at [datomic.promise$settable_future$reify__12002 get "promise.clj" 45]}]
 :trace
 [[datomic.promise$settable_future$reify__12002 get "promise.clj" 45]
  [clojure.core$deref_future invokeStatic "core.clj" 2317]
  [clojure.core$deref invokeStatic "core.clj" 2336]
  [clojure.core$deref invoke "core.clj" 2323]
  [datomic.promise$settable_future$reify__12002 get "promise.clj" 45]
  [clojure.core$deref_future invokeStatic "core.clj" 2317]
  [clojure.core$deref invokeStatic "core.clj" 2336]
  [clojure.core$deref invoke "core.clj" 2323]
  ... repeats ...

seancorfield06:02:11

I wonder if there's a (ClassName/member) style "call" in that code? Prior to Alpha 7, that was legal and the same as ClassName/member, but now it is an invocation. Nope, there is no change in this yet [edited in case anyone else reads this thread later].

seancorfield06:02:36

(datomic being closed source, we can't check)

Leaf Garland06:02:11

Perhaps. You might expect more java interop in promise related code.

hiredman06:02:15

I bet it is the change to the error message when deref is called on something not deferrable

seancorfield06:02:56

@U0NCTKEV8 That would cause a StackOverflow? 👀

seancorfield06:02:29

(there's a change to deref'able things to implement Supplier which might be more adjacent to this, if it isn't an accidental call of a static class member)

hiredman06:02:00

I bet they have a custom deref able thing that is also a future, and it implements the future get method by calling deref

hiredman06:02:11

In that case the deref function would call the deref method before, but now would call the future get

Bastian06:02:56

in the release notes it's stated that calling static class members will only become a problem in future releases

seancorfield06:02:15

I wasn't sure whether that meant 1.12 "GA" or 1.13...

Bastian06:02:33

yeah, i'm not sure now too :)

seancorfield06:02:15

But it does seem that Alpha 7 still allows (System/out) and treats it identically to System/out based on my (limited) testing.

👍 1
mkvlr06:02:24

we’re also running into this

flowthing08:02:30

Yeah, same here.

Alex Miller (Clojure team)10:02:20

There is no change in semantics in alpha7 for the static field invocation (nor will there be in 1.12), so more likely the deref thing.

ghadi13:02:52

hiredman wins the prize for the custom dereffable thing theory

🏆 7
hiredman17:02:54

thank you @U050ECB92, I have two things to say in accepting this prize: 1. hindsight is 20/20 2. I added "no scope 360 debugging" to my fediverse profile before I went to bed last night

🎯 2
seancorfield06:02:47

I suspect source code analysis tools are going to struggle with some of the new Alpha 7 syntax...

seancorfield06:02:55

(~/clojure)-(!2086)-> clj -Sdeps '{:deps {borkdude/edamame {:mvn/version "1.4.24"}}}'
Downloading: borkdude/edamame/1.4.24/edamame-1.4.24.pom from clojars
Downloading: borkdude/edamame/1.4.24/edamame-1.4.24.jar from clojars
Clojure 1.12.0-alpha7
user=> (require '[edamame.core :as e :refer [parse-string]])
nil
user=> (parse-string "(comp java.net.URI/getHost ^[String] java.net.URI/new)")
Execution error (IllegalArgumentException) at edamame.impl.parser/dispatch (parser.cljc:676).
Vector arg to map conj must be a pair
user=>

seancorfield06:02:37

(I've reported this in the #C04QVMQ39LG channel but I wonder how LSP and clj-rewrite and clj-kondo will all deal with this)

cfleming07:02:35

I was going to add support a while back, but Alex recommended waiting until the alpha was out. I’ll be adding support this weekend.

Alex Miller (Clojure team)10:02:49

There will need to be changes to tools.reader (already queued), tools.analyzer, and any other tool that analyzes source. Getting an alpha out there is the first step.

valerauko11:02:22

with alpha7 array parameter types get special treatment?

lread15:02:07

I'll test out how rewrite-clj handles 1.12 alpha and also the new syntax sometime soon.

seancorfield16:02:59

Using the full form of the type hint should work (borkdude pointed me in that direction): ^{:param-tags [String]}

lread16:02:45

Thanks, that makes sense. I'll start with verifying existing rewrite-clj tests all work under 1.12 alpha. Probably makes sense to add 1.12 to rewrite-clj CI at this point. I'll add git issues to rewrite-clj for new syntax after verifying it is not yet supported.

Alex Miller (Clojure team)16:02:50

yeah, that's the only reader change

👍 1
Jeff R. Allen12:02:20

I find it fascinating that clojure.lang.RT.specials is public, and that it's a persistent map, so theoretically I could assoc my own special form into it. Has anyone played with adding your own special form at runtime? Yes, this would be stupid/dangerous/non-standard/etc, but could it be useful?

respatialized12:02:30

Extending the read table is strongly discouraged for Clojure programs on the basis that it reduces interoperability and undermines the integrity of the "code as data" concept. Rich Hickey discusses the idea in the context of reader macros in https://dl.acm.org/doi/pdf/10.1145/3386321: > I saw reader macros in the CL style as being in direct conflict with library development, interoperability, Clojure data (edn) as a wire format etc. I am certain that had Clojure had reader macros, and users availed themselves of them, the large, composable, data-driven library ecosystem that arose around Clojure would have been compromised or thwarted.

Ed13:02:40

> it's a persistent map, so theoretically I could assoc my own special form into it it's also final and cos it's an immutable data structure, that means you can't do that, right? You'd have to use reflection or something to mess about with the internal representation? Or am I just being dumb?

Jeff R. Allen15:02:00

yup, you are exactly right. I saw the final and thought, "final, but I can just mutate the map". Because I was reading Java and it turned off the clojure part of my head! Anyway, it is really fascinating to see how simple the guts of Clojure really are.

Noah Bogart15:02:52

i meant to comment that the linked library is an implementation of "reader macros" in clojure, by doing some naughty stuff to remove the "final" tag from the specials and then allowing you to add your own. it works and it's cool, but i suspect folks wouldn't be happy about it if it was used in a library lol

chrisn13:02:58

It seems that https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Compiler.java#L6145 is permanently disabled - and that the only things cleared are done via clearing arguments. So various member variables around this - maxLocal, etc. are not used any more.

🐳 1
ghaskins14:02:35

I have a multi-method for downloading data from user-supplied URLs that dispatches based on the scheme in the URL. For test/repl scenarios, I want to support a resource:/// scheme, but I dont want this enabled in release builds. The two options I can think of to support such a notion would be to somehow conditionally compile the defmethod for the resource scheme, or to place the defmethod implementation in the ./test folders. I am not sure if the former exists and I am not clear on the mechanics for the latter (for instance, how do I ensure the code in the test classpath is loaded without requiring the namespace from the ./src classpath). Guidance appreciated.

p-himik14:02:15

> how do I ensure the code in the test classpath is loaded without requiring the namespace from the ./src classpath If there are two resources with the same URI on the classpath, the one found earlier will be used. So if you have both test and src on the classpath and they both have app/data.clj, if test is on the classpath earlier, then test/app/data.clj will be used. Alternatively, you can use a system property that you set only during development/testing. Or a .properties file that's not tracked into your VCS. Or an env variable.

ghaskins14:02:00

Those are good ideas I didnt think of. Ty!

jjttjj15:02:35

Post your shiny new Clojure alpha7 feature examples as well as small usage questions in this 🧵. These features are new and it'd be nice to see some examples small and large.

(map java.time.Instant/ofEpochMilli (range 10))

jjttjj15:02:14

Is there a way to make the param-tags work for something like this?

(^[] String/getBytes "hi") ;; works
(map  ^[] String/getBytes ["hi"]) ;;ClassNotFoundException [Bs

1
dpsutton15:02:42

i’m interested how to represent that

dpsutton15:02:09

user=> ^[] String/getBytes
Syntax error (ClassNotFoundException) compiling fn* at (REPL:6:1).
[Bs
so this syntax here will work in the future? It’s just a bug at the moment?

Noah Bogart15:02:52

i believe that's the case, yes. there's an attached patch which fixes it, if you want to see the test demonstrating this working

👍 2
Alex Miller (Clojure team)16:02:53

correct, that should work

👍 3
Alex Miller (Clojure team)16:02:25

it was working; we managed to break it just before we released it :)

😅 4
Alex Miller (Clojure team)16:02:08

these methods are truly values so you can pass them around too...

(let [len String/length] (map len ["abc" "a"]))
etc

Alex Miller (Clojure team)16:02:18

a useful property of the new uniform method symbols in invocation position is that you are explicitly providing sufficient information to identify one method - thus no inference happens AND you never have reflection (at the cost of being a bit more verbose).

👍 2
Alex Miller (Clojure team)16:02:56

one place where type hinting can particularly be a pain before these features was vararg overloads - the combo of the class array symbols and param tags removes most of the pain (but you still have to make the array)

escherize16:02:02

I’ve seen some libraries releasing un-namespaced reader macros. Is that unorthodox or downright naughty? I thought un-namespaced reader macros were supposed to be used only for future clojure core reader macros. If anything, what could or should be done about that?

p-himik16:02:13

> I thought un-namespaced reader macros were supposed to be used only for future clojure core reader macros That's correct. From https://clojure.org/reference/reader#tagged_literals: > Reader tags without namespace qualifiers are reserved for Clojure. > what could or should be done about that? Contact the developer of such a library, ask them if anything can be done at this point.

Alex Miller (Clojure team)16:02:30

yes, please (I have done so in the past)

Carsten Behring18:02:24

Is there any librarcy, which full automatic exposes a given clojure function as HTTP / JSON. I know about "the usual frameworks", but I want something even simpler, and out of the box. I just write the function, point to it and get a http server exposing it and marshals all input / outputs as json. (maybe restricted to "maps" of strings/numbers) Ideally giving me the Dockerfile as well

hiredman19:02:27

Not as complete as you are describing, and I am not sure I ever did a clojars release, but https://github.com/hiredman/graft/blob/master/src/graft/core.clj was a thing I fiddled with a while ago

vlaaad17:02:05

sorry for being super late, but mind if I ask what's your use case?

vlaaad17:02:15

I sorta can relate, a couple of times I had a need to build tiny servers which share a lot of verbose boilerplate and dependencies, (similar server/router/json lib/sqlite db...)

vlaaad17:02:28

so just curious what's your case 🙂

Noah Bogart19:02:14

i'm thinking about writing a clojure library that will be used in Java. what's the best way to expose a java API without forcing downstream users to use the Clojure.var business? aka IFn plus = Clojure.var("clojure.core", "+");

1
Alex Miller (Clojure team)19:02:32

create a Java API with interfaces and implement it in Clojure

Alex Miller (Clojure team)19:02:04

provide a factory method that does the bit of "make the Clojure thing" using the java api above

Alex Miller (Clojure team)19:02:03

writing an API in Java is the only way for it to have proper types and javadoc to describe what you present to Java users

👍 2
Noah Bogart19:02:19

so with a tools.build -based project, I'd have src/clj/noahtheduke/my-tool and src/java/noahtheduke/MyTool and then in the clojure code, I'd have (:import (noahtheduke.MyTool ITool)) and use it in whatever way, and then in the java, i'd have (my java is rusty, apologies) class PublicMyTool { static MyTool myMethod () { IFn makeTool = Clojure.var("noahtheduke.my-tool", "make-tool"); return makeTool.invoke(); } } and then when that's built into a jar with tools.build, java users could use import noahtheduke.MyTool.*; and call PublicMyTool.myMethod() etc.

Noah Bogart19:02:30

i know that's hard to read, sorry, i'm rubber ducking a little

Noah Bogart19:02:12

the interface sits at the top, the clojure code implements the interface and provides a clojure api, and then java code uses clojure.java.api.Clojure to wrap calls into the Clojure api, exposing a clean Java api

Noah Bogart19:02:30

cool, thank you

Alex Miller (Clojure team)19:02:56

yeah, just imagine Java users only see Java interfaces you have defined (the impls are provided by Clojure)

👍 1
seancorfield19:02:00

Alpha 6 release notes say "All IDeref impls (`delay`, future, atom, etc) now implement the Supplier interface directly." -- The Supplier behavior is all handled via default methods delegating to deref() -- nice -- what other dereffable things are there in core? ref and volatile! and reduced are the other ones I've found so far...

phronmophobic19:02:37

promise is another dereffable thing

Alex Miller (Clojure team)19:02:35

all the reference types

Alex Miller (Clojure team)19:02:51

that plus the list above are it pretty much

hiredman19:02:58

clojure.lang.Box doesn't oddly

Alex Miller (Clojure team)20:02:03

I just tried to hit the ones people actually use :)

Alex Miller (Clojure team)20:02:09

Box is not a user thing

Alex Miller (Clojure team)20:02:08

importantly it also extends to things outside core for custom IDerefs

Alex Miller (Clojure team)20:02:06

I didn't want to get down in the weeds in the release notes but it also satisfies all the Supplier variants - LongSupplier, BooleanSupplier, IntSupplier

👍 1
seancorfield20:02:43

Thank you, folks!

seancorfield20:02:41

I was looking for Supplier uses in our codebase and one particular pattern we have is for a supplier where each call to get() produces a new value (the body is side-effecting). I wonder if there would be value in having a macro that produced a IDeref value but whose deref() invokes the body each time? (supplier (compute something)) where the value wasn't cached but recomputed each time?

Alex Miller (Clojure team)20:02:28

we looked at that, it's pretty rare in the JDK to use Supplier like that (not sure if there is any use like that)

1
Alex Miller (Clojure team)20:02:39

we decided it was not a problem we needed to solve in core

1
seancorfield20:02:21

New Relic's TelemetryClient accepts a Supplier for an HTTP poster and they talk about both scenarios where you have a singleton supplier and where it returns a new instance for each get() call... But if it's not common in Javaland in general, I agree it doesn't need to be in core (and we can continue to reify Supplier here).

Alex Miller (Clojure team)20:02:42

with functional interface conversion you can just pass a stateful function too

seancorfield20:02:12

Yeah, looking forward to that alpha drop 🙂

seancorfield20:02:01

Hmm, I'm a bit surprised Supplier isn't used like that more often... ...on the plus side, this encouraged me to dig into the New Relic docs (and their forums) for a bit more detail about their telemetry client 🙂

Alex Miller (Clojure team)20:02:25

afaik, every other use is a 1-shot (basically a thunk)

seancorfield20:02:07

Maybe 0-arity functions should implement Supplier? 😈

Alex Miller (Clojure team)20:02:35

thought about that but the whole thing is that Supplier is not a function, don't encourage them :)

seancorfield20:02:50

Hence the little devil face there 😄

seancorfield23:02:39

FWIW, other than a few bumps already mentioned above, we're now running Clojure 1.12 Alpha 7 (dev/CI right now -- all tests pass, QA/Staging in about an hour I expect, not sure when this will make it to Production yet as we're in the middle of a bunch of fairly big feature changes).

nice 1