Fork me on GitHub
#clojure
<
2022-11-30
>
roklenarcic10:11:31

I want to call constructor of a Java class conditionally. If the branch is never reach, I don’t want JVM to load the class. What’s the best way to accomplish that?

lispyclouds10:11:02

Maybe try putting the (import ...) call inside the conditional branch?

Ed12:11:04

You could do the same thing you'd do in java? (.newInstance (Class/forName "..."))

armed14:11:48

Hey everyone, I’m trying to write a macro that reifies java.util.function.Consumer with type hints. Whenever I try to use it, clojure still prints reflection warning messages and the method (`.record`) could not be found in the runtime:

(defmacro as-callback
  [callback-fn long?]
  (let [result (gensym "result")
        meta-result (with-meta result {:tag (if long?
                                              ObservableLongMeasurement
                                              ObservableDoubleMeasurement)})]
    `(reify Consumer
       (accept [_# ~result]
         (let [{:keys [value# attributes#]} (~callback-fn)]
           (.record ~meta-result
                    value#
                    (otel.attributes/->attributes attributes#)))))))
Metadata is needed because an object in the result variable implements both interfaces and has an overloaded .record method with the same amount of arguments but different types. Approach with two simple functions works without any warnings:
(defn long-callback
  [callback-fn]
  (reify Consumer
    (accept [_ result]
      (let [{:keys [value attributes]} (callback-fn)]
        (.record ^ObservableLongMeasurement result
                 value
                 (otel.attributes/->attributes attributes))))))

(defn double-callback
  [callback-fn]
  (reify Consumer
    (accept [_ result]
      (let [{:keys [value attributes]} (callback-fn)]
        (.record ^ObservableDoubleMeasurement result
                 value
                 (otel.attributes/->attributes attributes))))))

(defn as-callback
  [callback-fn long?]
  (if long?
    (long-callback callback-fn)
    (double-callback callback-fn)))
Not sure what happens, what I am missing? macroexpand clearly shows that the method call has metadata (checked using (set! *print-meta* true))

armed10:12:16

answering to myself - :tag should be a fully qualified symbol, e.g. {:tag 'io.opentelemetry.api.metrics.ObservableLongMeasurement}, kudos to @U07FP7QJ0

👍 2
Akiz15:11:01

What is the rational behind allowing nil value in sets?

Akiz15:11:05

And if this is because this is how sets work in java. What is the rational in java?

delaguardo15:11:34

nil is just a value. there is no reason to treat it differently imho

Akiz15:11:59

That's right. I'm just wondering if Nil has ever been good to anyone in a set :)

Alex Miller (Clojure team)15:11:29

the rationale is: collections are heterogeneous collections of values and everything composes

👍 1
Alex Miller (Clojure team)15:11:56

(but admittedly nils in sets are rarely helpful)

isak16:11:38

It has been useful for me. For example let us say you have a vector of maps, and you want to check all of the distinct values for some key, and not all of the maps have the key.

isak16:11:40

If it wasn't possible to have nil in those sets it would just be completely bizarre and arbitrary

Alex Miller (Clojure team)16:11:46

the problem with nil (or false) in sets is that containment checks return a logically false value both when the nil/false is found and when they are not found

Akiz16:11:31

@U08JKUHA9 i would use (every? key coll-of-maps)

isak16:11:35

Is that if you just want to use the set as a function directly and not use the contains? function?

isak16:11:12

That doesn't do the same thing though, you are assuming my intention but that wasn't it

👌 1
Alex Miller (Clojure team)16:11:14

yes (remove my-set items) etc

isak16:11:32

Yea I see, I guess I've mostly avoided using sets that way

Akiz16:11:32

I am happy to know that there are use-cases where nil in set is useful. I often do something like this (empty? (set (map :d [{:a 1 :b 2} {:a 3} {:a 4 :b 5}]))) and when I forgot (filter identity ...) it usually leads to some bug 🙂

isak16:11:47

Too late now of course, but I wonder if having the IFn implementation of set be like contains? would be more useful than the current version where it returns itself?

isak16:11:29

Jakub for that one you could consider using keep instead of map initially

👏 2
Akiz17:11:52

So my feeling that there is a better way was right 😅

🙂 1
delaguardo17:11:53

or (every? #(contains? % :d) [{:a 1 :b 2} {:a 3} {:a 4 :b 5}]) to avoid set creation

Akiz17:11:20

@U04V4KLKC I need that set, using keep is a best solution in my case.

👍 1
mkvlr15:11:40

is there a thing like with-redefs but only affecting the current thread?

mkvlr15:11:58

that only works for vars that are ^:dynamic, right?

mkvlr15:11:29

in my case I want to change a non-dynamic thing

mkvlr15:11:54

I guess something like

(defn rebind [^clojure.lang.Var v f]
  (let [old (.getRawRoot v)]
    (.bindRoot v (f old))))

nbardiuk15:11:06

once I saw this gist https://gist.github.com/gfredericks/7143494 which probably later was extracted to a lib https://github.com/mourjo/dynamic-redef

mkvlr15:11:07

not quite…

mkvlr15:11:42

@U076FM90B thanks, that looks more like it!

👍 1
R.A. Porter15:11:46

That is a pretty solution.

borkdude13:12:33

@U5H74UNSF your rebind is basically what with-redefs also does, it's equally non-thread-safe (but should be good for testing purposes)

Colin P. Hill15:11:46

Can anyone think of a good reason that resolving aliases in custom tagged literals would be a bad idea? Context: Currently, tags are dispatched by their literal symbol, without resolving aliases, so this won't work:

(require '[my.long.namespace.name :as mlnn])
(set! *data-readers* {' mlnn/my-tag-reader}) ; or the equivalent in data_readers.clj
#mlnn/my-tag [:some :data :here]
It's possible, in principle, to make this work by binding *default-data-reader-fn* to a function which resolves aliases and looks up the result in *data-readers*. I'm tinkering with writing such a function, alongside some other tools for working with data readers. But the fact that alias resolution isn't supported natively makes me wonder whether that's a deliberate omission, and whether there's some good reason this shouldn't happen that I'm not seeing.

Alex Miller (Clojure team)15:11:28

aliases are specific to the namespace context you are in. tagged literals can potentially be read from any namespace. so those two things seem at odds to me.

Colin P. Hill15:11:29

There are a few libraries that include a data_readers.clj file. Because the Clojure documentation requires this, they are generally namespaced – but because nobody wants to work with excessively long names, these namespaces are generally extremely short, often one common word. To make up an imaginary example, if someone wrote an HTML library that uses readers, under common conventions their tags might be things like #html/element. Personally, I'm not a fan of short namespaces like this – I think there's a high risk of collision, which feels particularly uncomfy for things that are loaded automatically whenever they're present on the classpath. I'm noodling on the idea that improving the ergonomics of working with more deeply qualified namespaces on tags may make it feel a little safer to bundle readers into libraries. To answer your question, this isn't really something I need, but more of an experiment. To me, it feels pretty natural to declare a namespace alias at the top of my file and then use that alias in reader tags throughout. I'd even say it's counterintuitive (subjectively, to me) that this doesn't work. I'm having trouble seeing where the tension would be in this functionality.

Alex Miller (Clojure team)15:11:24

so you're talking about the qualifier on the tags, not on the impl

Colin P. Hill15:11:28

Correct. When defined – whether in a data_readers.clj file, or by binding the dynamic var – they'd still be fully qualified. But resolution would become sensitive to the aliases that are in effect in the context where they're read.

Colin P. Hill15:11:38

Not in principle different (...I think) from how vars in namespaces are always in themselves fully qualified, but may be referred to through aliases

Alex Miller (Clojure team)15:11:52

I think the issue is with when these things are resolved. tagged literals are resolved at read time. the reader does have access to the current context namespace aliases (via the mechanism for resolving autoresolved kws), but that raises the bar for some kinds of tooling. symbols are resolved at compile or eval time (so later).

Colin P. Hill15:11:12

Ah hm, I didn't realize symbols weren't resolved at read time. Possibly the prototypes I've been playing with won't work as soon as I move out of the REPL.

Alex Miller (Clojure team)15:11:42

I think there is some tension here with the goal of tagged literals too, which is to NOT tie tags necessarily to implementation details (the data_readers file is the binding mechanism there)

Colin P. Hill15:11:11

Actually wait, I did realize that :thinking_face: I'm mixing myself up by thinking of syntax-quotes, which do (I think?) resolve at compile time

Colin P. Hill15:11:11

What in this ties the tags to implementation details? I'm thinking of this analogously to :as-alias, where it's just a way to declare a shorthand which may or may not relate to a namespace where any actual code lives.

Colin P. Hill15:11:33

In practice it may even be used mostly with as-alias

Alex Miller (Clojure team)15:11:09

I don't know, I think this needs problem clarification before getting to this level

Colin P. Hill16:11:49

Fair enough, thanks for sharing your perspective. My immediate goal here is to build a prototype I can play with to see how it feels and what problems may arise. If it seems fine and I release it into the wild, I'll definitely make sure the README is festooned with warnings that the usage patterns it enables are experimental and may have undiscovered design issues.

richiardiandrea23:11:15

Hi folks, does anybody here know a bit of the internals of juji/editscript? I have got a conundrum/question around it

Huahai02:12:07

What’s your question?

richiardiandrea16:12:30

I have two structures that are quite different, say [{:a 2 :b: 3}] and [{:foo "bar"}] - I see the diff sometimes having the :- (remove), sometimes only having :r in it. I am not sure if I am doing something wrong or the diff is not deterministic...but the :- is very nice when you want to post-process the diff and, say, remove entities from the database

Huahai22:12:41

the algorithm is determistic, the same pair of data will have the same diff

richiardiandrea22:12:20

right, thank you that's a good correction of wording

richiardiandrea22:12:38

I hope the issue is clear enough though

Huahai22:12:39

they may differ among different version of editscript, for we may tweak the algo sometimes

Huahai22:12:48

it is unpredictable which one it will use, for the slight change in data may lead it to a different path

richiardiandrea22:12:56

I have noticed that if I increase the number of keys in the items above, say {:a 2 :c 3 :d 4 :e 5... the algo becomes less and less likely to detect a deletion

richiardiandrea22:12:12

yeah I think I noticed the same, thank you for confirming

Huahai22:12:38

the human eys’s sense of the size is not the same as the algo’s. The algo count size by number of nodes, so [] is a node itself, it counts

Huahai22:12:28

the original editscript many version ago count the size more like human, but i find that not our use case

richiardiandrea22:12:36

right, I think that's throwing me off, if I had a set maybe the deletion detection would be more consistent?

richiardiandrea22:12:06

basically I need a way to detect a deletion no matter the input size

Huahai22:12:13

editscript is not for human looking at the diff, it’s for machines, so it should be more like memory consumption

richiardiandrea22:12:16

yeah, the issue is not in me reading the edit script, it is more to consistently detect deletions

Huahai22:12:28

we can make the op size count configable, so one can tweak it to their liking

Huahai22:12:24

for example, if you prefer delete, make the cost of replacement high, delete low

Huahai22:12:44

please file an issue, so i can get to it sometime

Huahai23:12:33

the algo is driven by these cost scores, and it should be configurable

Huahai23:12:40

right now, they are fixed

Huahai23:12:08

with a huge cost of :r, you can effectively disable it

richiardiandrea23:12:51

ok sounds good, I will open one

richiardiandrea23:12:05

I think it would make sense to configure it /cc @U03219RPYTS @U01PAJR4N69 (my colleagues)

Huahai23:12:16

another option is to take out :r in config, so it is not even considered

richiardiandrea23:12:56

is it currently configurable?

Huahai23:12:13

not right now, but we can add both options

richiardiandrea23:12:40

ok sounds good, thank you for your help - will open an issue to track this

Huahai23:12:18

good. thanks.