clojure

New to Clojure? Try the #beginners channel. Official docs: https://clojure.org/ Searchable message archives: https://clojurians-log.clojureverse.org/
greglook 2021-06-09T00:47:55.181800Z

the BigInteger hash code is different by 60 :man-shrugging:

greglook 2021-06-09T00:48:32.182Z

at this point I don’t recall where I saw the hash code called out, maybe a very early Joy of Clojure edition? :thinking_face:

2021-06-09T00:48:55.182200Z

but the largest N you have seen so far might not be the largest N items by the time you reach the end, so you lose some stats about early occurrences of the largest N sometimes?

2021-06-09T00:57:19.185400Z

Need some help on this. Will you defprotocol Foobar with only a SINGLE defrecord FoobarImpl implementing the protocol? This way helps unit test so that we can write a defrecord FoobarTestImpl, but on the other side, I feel writing code in this way only for testing is unnecessarily complicated. Why not directly write functions working on the passed-in data? And we can use with-redefs to change the function logics under testing.

vemv 2021-06-09T10:37:47.199200Z

I do it and know of other teams also doing it it's the sort of thing that may look ugly from the outside, but once you just try it one sees only a useful, clean pattern that's not even particularly verbose (I'm a fan of implementing protocols via metadata; this also kills some code-reloading issues)

vemv 2021-06-09T10:38:28.199400Z

Interestingly, protocols can be considered to reify side-effects (or "side-causes"), yielding a functional (-ish) architecture

2021-06-11T07:59:52.294700Z

Hi. Didn’t quite get this part: protocols can be considered to reify side-effects (or “side-causes”), yielding a functional (-ish) architecture.

vemv 2021-06-11T09:18:42.294900Z

under vanilla clojure, if you want to perform a side-effect, you normally just do it, inline: (write-to-db! ...) such calls make a given defn impure. There's no automated way to analyse impure functions, instrument them, etc by having protocols to perform all side-effects, you can get a comprehensive listing all sorts of side-effects/side-causes going on in your codebase. It's easier to determine if a given defn is impure: if it receives an object that implements a protocol as an argument, then it's almost certainly impure there are various other gains as you can imagine: swapping implementations (for making tests faster/deterministic) etc

👍 1
seancorfield 2021-06-09T01:22:31.186200Z

I’m not a fan of creating a protocol purely for mocking during testing. That feels both too-OOP-ish and just plain unnecessary.

seancorfield 2021-06-09T01:23:47.187500Z

with-redefs has its problems but using functions feel like the “right” approach to me — why not pass in the function that you might otherwise want to redef? Or refactor your code so you don’t have a (presumably) side-effecting call in the middle of it?

souenzzo 2021-06-09T02:55:30.189600Z

When I call realized? on a "pending after start realize" delay it blocks my call until realized. Is it expected (repl example in the first comment)

souenzzo 2021-06-09T02:55:57.189700Z

(let [x (delay
          (Thread/sleep 1000))
      start (System/currentTimeMillis)
      diff! #(- (System/currentTimeMillis)
               start)]
  (prn [:before (realized? x) (diff!)])
  (future
    @x
    (prn [:after-deref (realized? x) (diff!)]))
  (Thread/sleep 100)
  (prn [:after-start-deref (realized? x) (diff!)]))
[:before false 0]
[:after-start-deref true 1001]
[:after-deref true 1001]
=> nil

dpsutton 2021-06-09T02:58:11.190700Z

I think there’s an IPending or something similar that gets involved with this

alexmiller 2021-06-09T03:01:45.191200Z

in the queue for 1.11

✔️ 1
Juλian (he/him) 2021-06-09T06:05:07.191700Z

regarding difference between Clojure's hash and Java's hashcode see https://clojure.org/guides/equality#equality_and_hash

pieterbreed 2021-06-09T08:27:06.195100Z

Has anybody here had to create POJOs before? I have a specific requirement to interface with jackson-databind, which runs on POJO's with specific Java annotations on the POJO classes, constructors and getters. Has anybody done this kind of thing before? I can get one POJO declared with gen-class, but the syntax is cumbersome for the many POJOs I need to create. I thought I'd use a macro to create the gen-classes for me, but with my own macro I can't pass in the meta-data that gen-class needs for annotations... Does anybody have some advice for me?

lassemaatta 2021-06-09T08:42:17.198700Z

I had a similar case when implementing a web service API where I needed java classes with lots of annotations (and no args constructors, mutable fields with setters,…) to generate the WSDL. In the end I decided to just define the classes as plain Java code, instead of constructing them by gen-class etal.

👍 1
henrik42 2021-06-09T10:51:34.199600Z

Have you tried using defrecord? It supports Annotations I believe. Some Java APIs need a default constructor though and in that case gen-class is all I've come up with when I needed it.

nod 2021-06-09T12:19:28.200500Z

Hey! Quick question: How can I efficiently update every nth element in a vector? As in, I want something faster than iterating over every single element. Thanks! (I just posted the same question on #beginners, not sure if I should have posted here instead)

p-himik 2021-06-09T12:21:03.200600Z

Vectors are associative collections, so just (assoc v 17 x).

p-himik 2021-06-09T12:21:22.200800Z

Oh, sorry, I missed the "every" word. Then just mapv.

nod 2021-06-09T12:33:45.201Z

Thanks! I tried to understand it but I don't see how that would be done (I'm still a beginner, sorry...) And wouldn't that still require iterating over the entire vector?

solf 2021-06-09T12:36:06.201200Z

A possible way using transients. This multiplies each 3rd element by 10

(let [data [1 2 3 4 5 6 7 8 9 10]
        step 3]
    (persistent!
     (reduce
      (fn [data i]
        (assoc! data i
                (* (get data i) 10)))
      (transient data)
      (range 0 (count data) step))))
  ;; [10 2 3 40 5 6 70 8 9 100]

solf 2021-06-09T12:38:25.201600Z

Ah but if you’re beginner there’s also the more straight-forward way without using transients:

(let [data [1 2 3 4 5 6 7 8 9 10]
        step 3]
    (reduce
     (fn [data i]
       (assoc data i
              (* (get data i) 10)))
     data
     (range 0 (count data) step)))
  ;; [10 2 3 40 5 6 70 8 9 100]

nod 2021-06-09T12:38:43.201800Z

Thank you! Do you know if this offers better performance than the solution Alex gave? I'll paste it here:

(loop [coll v, i 0]
  (if (< i (count v))
    (recur (assoc coll i (inc (nth coll i))) (+ i 10))
    coll))

solf 2021-06-09T12:40:00.202Z

it should be faster, yes I didn’t see the (+ i 10), it’s pretty much the same written differently

solf 2021-06-09T12:40:07.202200Z

but only marginally so?

solf 2021-06-09T12:40:32.202400Z

The transient version however should be noticeable faster. You could also add transients to Alex solution though

solf 2021-06-09T12:41:05.202600Z

Here’s the official guide if you’re interested in performance: https://clojure.org/reference/transients

p-himik 2021-06-09T12:41:19.202800Z

mapv uses transients by itself. Don't try to optimize without measuring and at places that aren't bottlenecks.

👍 1
solf 2021-06-09T12:42:46.203100Z

Fair point, but mapv would still have to loop over every item, which can be very bad depending on how big is the nth

p-himik 2021-06-09T12:48:24.203500Z

Ahh, right, I see - you have created a transient from the already existing data. Makes sense, and I'm especially blind today for some reason.

pieterbreed 2021-06-09T13:30:59.205600Z

I also tried defrecord but could not make it work

erwinrooijakkers 2021-06-09T13:34:28.205800Z

Since vector is associative you can use update as well with an index as second argument:

(update [0 0 0 0 0] 2 inc)
;; => [0 0 1 0 0]

erwinrooijakkers 2021-06-09T13:35:33.206Z

Ah I see there’s no transient version update!, that’s why above used assoc

solf 2021-06-09T13:42:48.206300Z

Indeed, for the non-transient version update is better

souenzzo 2021-06-09T15:18:21.208200Z

I'm not a JAVA guy and I just briefly know what a "POJO" is, but i thikn that these links can help https://github.com/clojure/java.data https://clojure.org/reference/datatypes#_java_annotation_support

john-shaffer 2021-06-09T15:22:03.209700Z

Any profiler recommendations? It's all Clojure code, and so far I just want to know which functions we're spending the most time in

alexmiller 2021-06-09T15:33:21.209900Z

https://github.com/clojure-goes-fast/clj-async-profiler

⛽ 1
alexmiller 2021-06-09T15:34:45.210700Z

probably the easiest clojure-oriented profiler. you can use any JVM profiler too (YourKit, JProfiler, VisualVM etc)

denik 2021-06-09T16:20:18.211400Z

Just published an article about Jive, an architecture where UI code is server-rendered but still web-based. This enables native backends with the reach of web. Give it a read and share your thoughts! https://kalavox.medium.com/jive-for-artisanal-software-2df0d675c104

🖤 1
emccue 2021-06-09T18:04:46.211900Z

emccue 2021-06-09T18:05:24.212100Z

> It doesn't exist yet

jumar 2021-06-09T18:37:47.213700Z

Bear in mind that by default it shows on-CPU time - if you are interested in wall clock time there’s another option for it

borkdude 2021-06-09T20:20:48.214600Z

Has a reflection cache been considered for Clojure? I.e. cache the lookup of the method based on the type of the receiver and types of args?

ghadi 2021-06-09T20:49:30.215800Z

What’s the unsaid problem that is trying to solve?

ghadi 2021-06-09T20:49:41.216200Z

(drink beverage of choice)

borkdude 2021-06-09T20:52:16.217100Z

@ghadi I'm just trying to gain information if something like this has been discussed before

borkdude 2021-06-09T20:54:09.218500Z

The problem could be that repetitive lookups are a waste, but I'm not sure if that is true. I'm just thinking out loud, hoping that someone will say something smart or will provide a link to an existing JIRA :)

borkdude 2021-06-09T20:59:26.220700Z

Context: I am working on an issue in the context of a graal-compiled binary where reflection works a bit different, since not all classes might have all information available, but sometimes methods can be found by visiting super classes and doing lookups on those, which seems quite wasteful to do repetitively. So I wondered if this topic had come up before.

ghadi 2021-06-09T21:07:11.222500Z

😂 at the ninja edit -- I saw it. I have only considered it in the context of making a cache at reflective callsites. That would reflect only at the first invocation, then remember the dispatch for subsequent invocations.

ghadi 2021-06-09T21:07:47.223300Z

for that use-case (slow "unresolved/reflective call" ), it's probably better to not reflect

ghadi 2021-06-09T21:07:54.223600Z

aka tell the developer to be explicit

ghadi 2021-06-09T21:08:25.224400Z

the topic of asking putting a method reflection cache in the compiler has come up some years ago

ghadi 2021-06-09T21:08:40.225Z

but again, that's an impl thing, not a problem thing

ghadi 2021-06-09T21:08:58.225300Z

can you describe the graal thing some more?

borkdude 2021-06-10T10:43:20.239300Z

Solved part 2

borkdude 2021-06-09T21:21:37.225500Z

yeah ok. two things: 1) the SCI interpreter is using reflection at runtime to perform interop calls (this can be optimized more, but that's how it works currently) 2) Graal native binaries support reflection configs. This makes it possible to reflect at runtime like you would in the JVM. But if you don't provide a config for class X let's say, and you wanted to call Object.notify on an instance of X, you would reflect on the class X, but find nothing. However, when you visit the superclass, e.g. Object, and you had a reflection config for Object, then you would still find notify and would be able to call it. This is more work than you would normally have to do on the JVM in the clojure.lang.Reflector. Depending on which class you hit, you would hit that path or not, so I would have to do some benchmarking etc to see how bad the overhead is there, but that's where I'm coming from.

alexmiller 2021-06-09T21:42:33.226400Z

I don't know of anything like this in jira. The general rule is if it matters, stop using reflection. So, not much interest historically in trying to optimize the not optimized case.

✔️ 2
borkdude 2021-06-09T21:43:22.226600Z

ok, thanks

awb99 2021-06-09T22:39:24.229100Z

I have a weird bug when working with RELEASE dependencies: "clojure -X:notebook" brings this error Execution error (FileNotFoundException) at clojure.run.exec/requiring-resolve' (exec.clj:31). but "clojure -P -X:notebook" works fie. Thishappens only when there is no artefact of the dependency in .m2 cache. Is there a shortcut that works in all circumstances?

2021-06-09T23:33:20.229700Z

you have a stale classpath cache

2021-06-09T23:34:06.230400Z

clj caches the calculated classpath between executions to speed up startup

2021-06-09T23:34:38.231Z

(goes in ./.cpcache)

2021-06-09T23:35:22.231800Z

you are running the clojure script in an evinronment where the cache exists, and tells it the dep is in ~/.m2, but that isn't the case