clojure

New to Clojure? Try the #beginners channel. Official docs: https://clojure.org/ Searchable message archives: https://clojurians-log.clojureverse.org/
devn 2021-03-02T01:25:41.399600Z

well, aside from a lot of us in IRC trying to break it all the time for years, I agree 😄

devn 2021-03-02T01:30:30.399800Z

it also does the nice thing and will ignore thing if it is prepended with _, like _thing to signal unused

Valentín 2021-03-02T03:08:51.400200Z

Hi everybody

Valentín 2021-03-02T03:09:49.400900Z

does somebody know how to convert this java line code into clojure code?

Valentín 2021-03-02T03:09:53.401100Z

this.API = (WindowsNamedPipeLibrary) Native.loadLibrary("kernel32", WindowsNamedPipeLibrary.class, W32APIOptions.UNICODE_OPTIONS)

Valentín 2021-03-02T03:10:20.401800Z

I've been trying this...

Valentín 2021-03-02T03:11:24.402Z

(defn get-API []
  ;this.API = (WindowsNamedPipeLibrary) Native.loadLibrary("kernel32", WindowsNamedPipeLibrary.class, W32APIOptions.UNICODE_OPTIONS)
  (let [interface-class (.getClass osquery-clj.interfaces.IWindowsNamedPipeLibrary)
        unicode-options (W32APIOptions/UNICODE_OPTIONS)
        API ^osquery-clj.interfaces.IWindowsNamedPipeLibrary (Native/loadLibrary "kernel32" interface-class unicode-options)]
    API))

2021-03-02T03:13:38.402900Z

You should print out the value of interface-class

phronmophobic 2021-03-02T03:22:46.404600Z

what error are you getting?

Valentín 2021-03-02T03:22:53.404800Z

Im getting that error Interface (Class) of library=kernel32 does not extend Library

phronmophobic 2021-03-02T03:25:25.405900Z

For JNA, I've been using something like:

(def objlib (try
              (com.sun.jna.NativeLibrary/getInstance "CoreFoundation")
              (catch java.lang.UnsatisfiedLinkError e
                nil)))
It looks like you can pass in an options map to this call too. Does this work for you?
(def api (try
              (com.sun.jna.NativeLibrary/getInstance "kernel32" (W32APIOptions/UNICODE_OPTIONS))
              (catch java.lang.UnsatisfiedLinkError e
                nil)))

seancorfield 2021-03-02T03:29:54.406600Z

UNICODE_OPTIONS is not a function so the parens look wrong around that.

p-himik 2021-03-02T09:50:58.421200Z

I remember reading the code in Clojure compiler that would explicitly turn (MyClass/STATIC_FIELD) into a regular static field lookup. Can't quickly find it right now though. Perhaps it even worked that way for (.regularNotCallableField myObject)...

phronmophobic 2021-03-02T03:30:35.407200Z

that part works though

> (W32APIOptions/UNICODE_OPTIONS)
{"type-mapper" #object[com.sun.jna.win32.W32APITypeMapper 0x4a9f4493 "com.sun.jna.win32.W32APITypeMapper@4a9f4493"], "function-mapper" #object[com.sun.jna.win32.W32APIFunctionMapper 0x703d3680 "com.sun.jna.win32.W32APIFunctionMapper@703d3680"]}
¯\(ツ)

phronmophobic 2021-03-02T03:30:57.407400Z

it also works without the parens :thinking_face:

phronmophobic 2021-03-02T03:32:53.408Z

that block is from my repl, so I can confirm it works with and without parens

phronmophobic 2021-03-02T03:33:03.408200Z

unless my repl is doing something goofy

Valentín 2021-03-02T03:33:20.408700Z

now it seems it is working

Valentín 2021-03-02T03:33:32.409100Z

(defn get-API []
  ;this.API = (WindowsNamedPipeLibrary) Native.loadLibrary("kernel32", WindowsNamedPipeLibrary.class, W32APIOptions.UNICODE_OPTIONS)
  (let [interface-class osquery-clj.interfaces.IWindowsNamedPipeLibrary
        unicode-options W32APIOptions/UNICODE_OPTIONS
        API ^osquery-clj.interfaces.IWindowsNamedPipeLibrary (Native/loadLibrary "kernel32" interface-class unicode-options)]
    API))

seancorfield 2021-03-02T03:33:46.409600Z

And as for WindowsNamedPipeLibrary.class, in Clojure the class name evaluates to the class itself, so WindowsNamedPipeLibrary should be all you need?

Valentín 2021-03-02T03:34:20.409900Z

yes you are right

seancorfield 2021-03-02T03:35:29.410500Z

I'm just kind of puzzled by a Java interface that seems to have data members...

Valentín 2021-03-02T03:35:43.410800Z

with that change it seems its working

seancorfield 2021-03-02T03:36:09.411100Z

My Java is rustier than I thought? 🙂

Valentín 2021-03-02T03:36:34.411500Z

thanks all

phronmophobic 2021-03-02T03:36:37.411600Z

there's some odd things in JNA to make interop with c better

phronmophobic 2021-03-02T03:36:58.411800Z

honestly, I'm not sure how all of it works

seancorfield 2021-03-02T03:38:15.412100Z

Apparently you can declare variables (data members) in an interface and they are treated as static final. TIL.

1
raspasov 2021-03-02T04:53:50.412400Z

@pez hmm that sounds quite strange (esp the 200x)… what kind of code are you running and how many cores is the machine? What’s the (pipeline n …) number?

raspasov 2021-03-02T04:54:40.412600Z

Is it pure functions or is there IO in the code?

pez 2021-03-02T06:52:39.412800Z

I’ll make a repro.

pez 2021-03-02T07:52:37.413100Z

I think this is similar enough to what I do in my program, where I have a boolean-array where some positions are set, and some are not. Most are not. Then I want the indexes of the set bits of every odd position from the array, as a sequence.

(let [n 1000000
      ba (boolean-array n)
      every-other (range 1 n 2)
      prob 0.15
      sample-size (long (* n prob))
      to-ch (a/chan 1)
      from-ch (a/to-chan every-other)]
  (doseq [i (take sample-size
                  (random-sample prob (range n)))]
    (aset ba i true))

  (println "filter")
  (time
   (count
    (filter #(aget ba %) every-other)))

  (println "transduce")
  (time
   (count
    (transduce
     (filter #(aget ba %))
     conj
     every-other)))

  (println "core.reducers/filter")
  (time
   (count
    (into [] (r/filter #(aget ba %) every-other))))

  (println "core.async/pipeline")
  (time
   (do
     (a/pipeline 4 to-ch (filter #(aget ba %)) from-ch)
     (count
      (a/<!! (a/into [] to-ch))))))

pez 2021-03-02T07:54:04.413300Z

Output:

filter
"Elapsed time: 24.779003 msecs"
transduce
"Elapsed time: 23.854725 msecs"
core.reducers/filter
"Elapsed time: 23.759016 msecs"
core.async/pipeline
"Elapsed time: 3535.955765 msecs"
=> 74885

pez 2021-03-02T08:00:37.413500Z

If I use criterium/quick-bench instead, the transduce and reducers wins are a bit more appearant:

filter
Evaluation count : 30 in 6 samples of 5 calls.
             Execution time mean : 23,654346 ms
    Execution time std-deviation : 301,776435 µs
   Execution time lower quantile : 23,352585 ms ( 2,5%)
   Execution time upper quantile : 24,050820 ms (97,5%)
                   Overhead used : 14,507923 ns
transduce
Evaluation count : 36 in 6 samples of 6 calls.
             Execution time mean : 20,129352 ms
    Execution time std-deviation : 595,084459 µs
   Execution time lower quantile : 19,646010 ms ( 2,5%)
   Execution time upper quantile : 21,079716 ms (97,5%)
                   Overhead used : 14,507923 ns
core.reducers/filter
Evaluation count : 36 in 6 samples of 6 calls.
             Execution time mean : 17,903643 ms
    Execution time std-deviation : 186,971423 µs
   Execution time lower quantile : 17,675913 ms ( 2,5%)
   Execution time upper quantile : 18,138291 ms (97,5%)
                   Overhead used : 14,507923 ns
core.async/pipeline
Evaluation count : 22230 in 6 samples of 3705 calls.
             Execution time mean : 27,089463 µs
    Execution time std-deviation : 136,898899 ns
   Execution time lower quantile : 26,919838 µs ( 2,5%)
   Execution time upper quantile : 27,291471 µs (97,5%)
                   Overhead used : 14,507923 ns
(For some reason, it fails to measure the pipeline code. It doesn’t in my real code.)

pez 2021-03-02T08:44:05.413900Z

Interestingly (to me, at least 😄 ) for performs on par with transduce with this task:

(println "for")
    (quick-bench #_time
                 (count
                  (for [i every-other
                        :when (aget ba i)]
                    i)))

for
Evaluation count : 36 in 6 samples of 6 calls.
             Execution time mean : 19,456574 ms
    Execution time std-deviation : 100,364503 µs
   Execution time lower quantile : 19,370228 ms ( 2,5%)
   Execution time upper quantile : 19,618312 ms (97,5%)
                   Overhead used : 14,507923 ns

vandr0iy 2021-03-02T09:06:23.415500Z

Hi everybody! I gotta hook up a call (sentry 🙂 ) to all of the exceptions (`Throwable`s) in my application. Is there a nice AOP way to do it by adding a hook somewhere once?

lassemaatta 2021-03-02T09:21:20.415600Z

What kind of application are you developing? For example with a HTTP stack you can create a http middleware, which catches and re-throws the exceptions thrown by the handler(s) and reports them to sentry

dharrigan 2021-03-02T09:28:59.415800Z

You can try this:

dharrigan 2021-03-02T09:29:02.416Z

(defn ^:private set-default-exception-handler
  [sentry-logger]
  (Thread/setDefaultUncaughtExceptionHandler
   (reify Thread$UncaughtExceptionHandler
     (uncaughtException [_ thread ex]
       (log/warn ex "Uncaught Exception!")
       (sentry-logger {:throwable ex})))))

1👍
dharrigan 2021-03-02T09:29:33.416200Z

You simply need to then provide a sentry-logger, which is a function that creates a sentry instance, configured as you see fit...

vandr0iy 2021-03-02T09:30:08.416400Z

hmmm ☝️ that's one way to do it

dharrigan 2021-03-02T09:30:23.416600Z

Works for moi in my application 🙂

vandr0iy 2021-03-02T09:30:54.416800Z

of course, I'd have to add the sentry hook to all of the caught exceptions - but that's mostly search and replace

vandr0iy 2021-03-02T09:31:09.417Z

yeah, I like this one. Thank you!

dharrigan 2021-03-02T09:31:26.417200Z

you're welcome. 🙂

dharrigan 2021-03-02T09:31:41.417500Z

btw, which sentry library are you using?

vandr0iy 2021-03-02T09:32:00.417700Z

I think I'll go with the official one. Got any reccomendations?

dharrigan 2021-03-02T09:32:18.417900Z

Which one would that be?

lassemaatta 2021-03-02T09:33:32.418100Z

I recently had some problems with the official one (`sentry-clj`?), it failed to report some clojure exceptions properly. raven-clj did not have this issue.

dharrigan 2021-03-02T09:33:56.418400Z

Which version of the sentry-clj are you using?

p-himik 2021-03-02T09:34:07.418600Z

Out of curiosity - what about a plain loop?

vandr0iy 2021-03-02T09:34:24.418800Z

@dharrigan sentry-clj

lassemaatta 2021-03-02T09:34:29.419Z

good question, I believe I tried the latest one a few weeks ago

vandr0iy 2021-03-02T09:34:49.419200Z

I also saw one from exoscale - is it worth it? which one are you using?

dharrigan 2021-03-02T09:35:04.419400Z

I'm maintaining the semi-official one

lassemaatta 2021-03-02T09:35:28.419600Z

(sorry, I didn't mean to hijack this thread with my own issues 😄 )

dharrigan 2021-03-02T09:35:31.419800Z

sentry-clj isn't official, in the sense that it's not sanctioned by Sentry. It's deemed a community-driven effort

raspasov 2021-03-02T09:36:01.420Z

@pez I see… Ok, I think the biggest gains from pipeline are to be had when the pipeline transducer is CPU intensive (think like parsing HTML into data, file compression, etc); here you have a pretty straightforward xf (filter #(aget ba %)) Also, I think 1,000,000 samples is not that much really, so (pipeline …) would be suffering from all the channel, etc overhead of passing the data around;

dharrigan 2021-03-02T09:36:05.420200Z

If you have issues with sentry-clj, raise an issue on github and I'll see what I can do 🙂

dharrigan 2021-03-02T09:36:33.420400Z

PRs are welcome 'tho 🙂

raspasov 2021-03-02T09:38:51.420600Z

Also, a sidenote, (time …) is almost never a good benchmark strategy (but quick-bench is); I’ve seen cases where a simple (time …) benchmark would be “slow” but quick-bench would actually show a huge improvement since the JVM does its JIT magic and code really speeds up after a few iterations in some cases;

raspasov 2021-03-02T09:39:27.420800Z

I think that’s a good idea @p-himik (loop []…)

raspasov 2021-03-02T09:39:59.421Z

That’s probably the fastest thing you can get in terms of raw single thread perf… pretty much Java speed;

p-himik 2021-03-02T09:50:58.421200Z

I remember reading the code in Clojure compiler that would explicitly turn (MyClass/STATIC_FIELD) into a regular static field lookup. Can't quickly find it right now though. Perhaps it even worked that way for (.regularNotCallableField myObject)...

pez 2021-03-02T10:08:36.421400Z

BOOM

(println "loop")
(quick-bench #_time
             (count
              (loop [res []
                     i 1]
                (if (<= i n)
                  (recur (if (aget ba i)
                           (conj res i)
                           res)
                         (+ i 2))
                  res))))

loop
Evaluation count : 84 in 6 samples of 14 calls.
             Execution time mean : 7,518441 ms
filter
Evaluation count : 30 in 6 samples of 5 calls.
             Execution time mean : 23,020098 ms
transduce
Evaluation count : 36 in 6 samples of 6 calls.
             Execution time mean : 19,090405 ms
core.reducers/filter
Evaluation count : 42 in 6 samples of 7 calls.
             Execution time mean : 16,328693 ms
for
Evaluation count : 36 in 6 samples of 6 calls.
             Execution time mean : 19,678977 ms

raspasov 2021-03-02T10:14:27.421700Z

Yup, loop is the king 🙂

raspasov 2021-03-02T10:14:48.421900Z

If you really care about perf. I highly recommend YourKit

raspasov 2021-03-02T10:15:18.422100Z

I bet it will help you gain 50% in no time

raspasov 2021-03-02T10:15:44.422300Z

I’ve used it, it’s like magic; the gains will come from a place you least expect… some reflection call that’s using 50% of your CPU time

p-himik 2021-03-02T10:16:47.422600Z

@pez Now try making res a transient. :)

pez 2021-03-02T10:17:26.422800Z

transient, huh? Doin’ it!

raspasov 2021-03-02T10:18:51.423Z

Try also unchecked-math 🙂

1➕
p-himik 2021-03-02T10:20:26.423300Z

In my previous adventure with single-threaded high perf, I ended up writing a Java class. :D All my data consisted of integers and Clojure doesn't really like them.

raspasov 2021-03-02T10:20:31.423500Z

Also, http://clojure-goes-fast.com (various ideas how to go fast)

pez 2021-03-02T10:21:25.423900Z

I’ll be trying YourKit too. Though only out of curiosity really. I don’t have performance tasks often. This is a little toy challenge I have, mainly to learn more about Clojure. I profile it with tufte right now, which is pretty nice.

pez 2021-03-02T10:24:11.424400Z

Seems like I should be able to parallelize the loop, no?

p-himik 2021-03-02T10:25:25.424600Z

Absolutely, your problem is a textbook map(filter)/reduce problem.

borkdude 2021-03-02T10:36:38.425100Z

I'm a bit surprised that transit doesn't offer support for serializing arrays out of the box:

user=> (write-transit [1 2 3])
"[1,2,3]"
user=> (write-transit (into-array [1 2 3]))
Execution error (NullPointerException) at com.cognitect.transit.impl.AbstractEmitter/marshalTop (AbstractEmitter.java:203).
null

raspasov 2021-03-02T11:00:23.425400Z

I guess it focuses on Clojure data, and arrays are host-specific things:

raspasov 2021-03-02T11:00:35.425700Z

(into-array [1 2 3]) => #object[“[Ljava.lang.Long;” 0x55cad8a0 “[Ljava.lang.Long;@55cad8a0"]

borkdude 2021-03-02T11:02:16.425900Z

So are byte arrays, yet it supports them:

user=> (write-transit (.getBytes "foo"))
"[\"~#'\",\"~bZm9v\"]"

raspasov 2021-03-02T11:04:11.426300Z

I see… I don’t have other guesses 🙂

Timofey Sitnikov 2021-03-02T12:39:54.428800Z

Good Morning Clojurians, if I make a mistake and require something that I should not have, and get this:

user=> (require 'development)
Syntax error (FileNotFoundException) compiling at (app/model/session.clj:1:1).
Could not locate datascript/core__init.class, datascript/core.clj or datascript/core.cljc on classpath.
It seems like after fixing the issue, I have to completely restart the REPL for it to work properly. Would there be a process to fix and not have to restart the REPL?

borkdude 2021-03-02T12:45:33.429400Z

@timofey.sitnikov in the leiningen world you have pomegranate for this, in the deps.edn world there is something called add-lib

p-himik 2021-03-02T12:45:38.429500Z

Yes. You can use a different classloader that allows adding things to the classpath in runtime. While it may sound complicated, there are already implementations out there. Probably the easiest way to start using such functionality is to look at Sean Corfield's dot-clojure repo: https://github.com/seancorfield/dot-clojure Namely, search for :add-libs in the README.

1
p-himik 2021-03-02T12:46:03.429800Z

(I'm assuming you're using deps.edn)

Ben Sless 2021-03-02T13:54:27.430400Z

I there a way to override a specific method implementation in a defrecord?

borkdude 2021-03-02T14:20:40.430700Z

Hmm, maybe :extend-via-metadata helps somehow?

user=> (defprotocol Foo :extend-via-metadata true (foo [_]) (bar [_]))
Foo
user=> (defrecord FooRec [] Foo (foo [_] :foo) (bar [_] :bar))
user.FooRec
user=> (foo (->FooRec))
:foo
user=> (foo (with-meta (->FooRec) {`foo (fn [_] :overriden)}))
:foo
user=> (foo (with-meta (into {} (->FooRec)) {`foo (fn [_] :overriden)}))
:overriden
:thinking_face:

borkdude 2021-03-02T14:21:21.430900Z

But not really I think

borkdude 2021-03-02T14:21:39.431100Z

Do you mean a defrecord instance of the defrecord type btw?

Ben Sless 2021-03-02T14:23:55.431300Z

The idea was to override the equality methods for a record, but I can roll my own with a minimal deftype

borkdude 2021-03-02T14:24:39.431500Z

oh right

Ben Sless 2021-03-02T14:25:16.431700Z

Things got less pleasant where I had to implement my own hasheq 😞

alexmiller 2021-03-02T14:38:12.431900Z

you should not do this

alexmiller 2021-03-02T14:38:35.432100Z

if you want custom equality/hashing semantics, you should deftype

nooga 2021-03-02T15:21:15.434300Z

dumb question about internals: is the compiler supposed to evaluate each top level form one-by-one when compiling? it has to learn about macros somehow as it goes

nooga 2021-03-02T15:21:51.434800Z

or is there some more advanced magic involved?

alexmiller 2021-03-02T15:23:17.435200Z

the compiler first reads (string -> clojure data)

alexmiller 2021-03-02T15:23:49.435800Z

then compiles, then evaluates

emccue 2021-03-02T15:24:34.436600Z

@vandr0iy you can make your own try catch

alexmiller 2021-03-02T15:24:35.436800Z

compiling an expr will look at the thing in function position. if that's a macro, it expands the macro (this happens until it's not a macro)

emccue 2021-03-02T15:24:40.436900Z

thats always on the table

alexmiller 2021-03-02T15:25:19.438200Z

a macro is just a function that takes a form (clojure data representing a function call) as input and returns an alternate form (clojure data) to replace it with

emccue 2021-03-02T15:25:34.438600Z

not recommending it but you can always make

(custom/try
   ...
   (catch RuntimeException e
     ...)
   (finally
     ...))

emccue 2021-03-02T15:25:46.439100Z

and expand it to have whatever calls to sentry you want

alexmiller 2021-03-02T15:25:50.439400Z

the unit of compilation/evaluation is a single top-level form (not a file)

1👍
emccue 2021-03-02T15:25:53.439500Z

that would be the AOP-iest way

nooga 2021-03-02T15:26:31.440300Z

yes, but defmacro is basically (do (defn x ...) (set-macro! (var x))) and that set-macro! call has to be evaluated for the compiler to know that x is a macro

nooga 2021-03-02T15:26:47.440700Z

ah right, that’s what I was wondering about

nooga 2021-03-02T15:26:57.441Z

thanks @alexmiller 👍

nooga 2021-03-02T15:27:55.441100Z

obviously it is not called set-macro! in Clojure, used that name for brevity

Ben Sless 2021-03-02T17:23:06.441800Z

That's what I ended up doing

p-himik 2021-03-02T18:06:38.442400Z

Could someone please point me to the repo that tracks the Clojure CLI bash script?

p-himik 2021-03-02T18:09:17.443Z

Thanks! Would've never thought to look in something that has "brew" in its name. :) And for some reason Google doesn't index the repo.

seancorfield 2021-03-02T18:17:35.443200Z

https://clojure.org/releases/tools is also a useful reference, listing all the releases and the changes in each.

1👍
p-himik 2021-03-02T18:30:51.446400Z

I'm trying to use clojure.tools.namespace.repl/refresh and I've stumbled upon an interesting issue. When called for the first time, it seems to reload absolutely all Clojure files that it could find in the classpath. Regardless of whether they have been loaded before or not. The problem is that I have a few files that aren't loaded and require extra dependencies to be loaded. Clearly, I don't want refresh to load them at all. Is it possible to fix it on my end? Would it make sense to alter something in clojure.tools.namespace to support reloading only the files that have been loaded before?

pez 2021-03-02T18:34:35.448200Z

transient shaves some more of the time, as hinted at 😃

loop
             Execution time mean : 7,704050 ms
loop-transient
             Execution time mean : 5,017702 ms
filter
             Execution time mean : 24,047486 ms
transduce
             Execution time mean : 19,687393 ms
core.reducers/filter
             Execution time mean : 17,303117 ms
for
             Execution time mean : 21,142251 ms

1👍
mkvlr 2021-03-02T18:34:38.448400Z

we’re also seeing this, iirc it’s a problem with tools namespace not seeding the timestamp it uses to track what needs to be compiled directly

p-himik 2021-03-02T18:35:43.448600Z

Not sure. The docstring explicitly says that it will load all files upon the first call: > Scans source code directories for files which have changed (since the last time this function was run)

mkvlr 2021-03-02T18:39:09.450200Z

yeah, might well be a design decision but it’s annoying in our project where you need to wait forever the first time you call it

mkvlr 2021-03-02T18:39:39.451500Z

preseeding this timestamp might be worth a try

p-himik 2021-03-02T18:40:30.451700Z

Oh, that might help, I'll try that!

mkvlr 2021-03-02T18:43:04.452Z

please let me know if it does!

alexmiller 2021-03-02T18:48:48.453100Z

Yes, the repo name is bad and we have a ticket for that (but it requires updating a bunch of infrastructure so has not seemed worth it so far)

2021-03-02T18:49:21.453900Z

PSA: Clojars is having DNS issues - our provider (DNSimple) is having an outage, which is making it impossible to resolve http://clojars.org in some parts of the world. Hopefully they will get it fixed soon.

1❤️
alexmiller 2021-03-02T18:49:57.455Z

Note that the script linked above does have some variable replacement done on it before it gets published so you can’t just use it as is

p-himik 2021-03-02T18:49:59.455200Z

OK, adding

(alter-var-root #'clojure.tools.namespace.repl/refresh-tracker
                assoc :clojure.tools.namespace.dir/time (System/currentTimeMillis))
seems to work. However, it truly fixes only the initial loading issue. It will not fix a situation where you change some file that has not yet been loaded (and that cannot be loaded due to a missing dep for example) and then call refresh.

1👍
alexmiller 2021-03-02T18:51:00.456500Z

Often when people ask this, their real need is something else which might have a better answer if you care to share

p-himik 2021-03-02T18:51:57.456700Z

Thanks! Yeah, I was just curious about the history of commits that first introduced clojure.libfile and later removed it. Cursive seems to still set the clojure.libfile property.

NoahTheDuke 2021-03-02T18:53:49.457100Z

this looks super cool. do you have any examples of usage?

alexmiller 2021-03-02T19:10:29.459100Z

Ah, yeah, that’s dead, replaced by the basis property. I was setting both so add-lib would keep working but that’s updated now

1👍
NoahTheDuke 2021-03-02T19:28:15.459600Z

awesome, thank you!

p-himik 2021-03-02T19:30:07.459800Z

Got it working properly (or at least, as I want it to work) with this:

(alter-var-root #'clojure.tools.namespace.repl/remove-disabled
                (fn [orig-remove-disabled]
                  (fn [tracker]
                    (let [filter-loaded #(filter find-ns %)]
                      (-> tracker
                          orig-remove-disabled
                          (update :clojure.tools.namespace.track/unload filter-loaded)
                          (update :clojure.tools.namespace.track/load filter-loaded))))))

p-himik 2021-03-02T19:33:49.460Z

@alexmiller You're the latest contributor to tools.namespace - do you have any thoughts on the above? Would it make sense to add such a behavior to the lib, perhaps under a flag or via a function that changers some var, like disable-reload! already does?

alexmiller 2021-03-02T19:34:14.460200Z

please file a question on ask.clojure..

1👍
alexmiller 2021-03-02T19:34:20.460500Z

don't have time to look at it atm

2021-03-02T19:41:14.462500Z

I remember I found a tool similar to Ansible but written in Clojure, it’s not pallet, it was recently developed, I can’t find. any idea?

lukasz 2021-03-02T19:45:32.462700Z

Spire? https://github.com/epiccastle/spire

pez 2021-03-02T19:52:42.463400Z

Unchecked math doesn’t seem to make much of a difference for the particular problem.

p-himik 2021-03-02T19:58:10.463600Z

I think that's because there's only a single math operation there, and its arguments' types are well known by the compiler. If you really want to pursue it further, I would try to get the bytecode for that code and see if there's something fishy going on. I've had some success with https://github.com/gtrak/no.disassemble/ and https://github.com/clojure-goes-fast/clj-java-decompiler before.

2021-03-02T20:04:27.464300Z

Yes thank you

vemv 2021-03-02T20:19:20.464600Z

Looks like you aren't invoking set-refresh-dirs beforehand? It's very recommendable to do so

p-himik 2021-03-02T20:24:08.464800Z

It still doesn't solve item 1 in the post above. It's easy to forget to add a newly created dir there. It's impossible to have a file that you don't want to load in the same dir with a file that should be reloaded.

vemv 2021-03-02T20:27:32.465Z

> It's easy to forget to add a newly created dir there. Can be solved in a number of ways; this is not a place to question t.n's API/design. > It will attempt to (re)load even the files that haven't been loaded before. This doesn't make sense, t.n's very job is loading code. Its first load will typically load all your project's code; if you aren't doing this you are following a custom/hybrid approach

p-himik 2021-03-02T20:31:14.465200Z

And I don't think that it's an invalid approach. At the very least, mkvlr above seems to share it with me.

mkvlr 2021-03-02T20:37:50.467100Z

@vemv IMO there’s nothing to reload when you call refresh after you project boots without code changes

vemv 2021-03-02T20:40:14.467600Z

there's everything to reload because nothing can be assumed to have been required. If something else was requireing your code, making refresh perceivedly redundant, you should have a careful look at what/why is doing that. https://github.com/stuartsierra/reloaded is the canonical example of how to setup a project using t.n.

p-himik 2021-03-02T20:43:55.467900Z

Still, it doesn't invalidate the desire to be able to adhere to, as you called it, a custom/hybrid approach.

vemv 2021-03-02T20:45:33.468100Z

I didn't suggest so

pez 2021-03-02T20:57:40.468700Z

Unchecked doesn’t attract me so much. I would rather to figure out how to parallellize it. I can’t immediately see how:

(quick-bench #_time
                 (count
                  (loop [res []
                         i 1]
                    (if (<= i n)
                      (recur (if (aget ba i)
                               (conj res i)
                               res)
                             (+ i 2))
                      res))))

p-himik 2021-03-02T20:59:10.468900Z

- Split ba into N chunks - For each chunk, run a thread that creates its own res - Combine the resulting collection of res vectors in a single vector, preserving the order

p-himik 2021-03-02T20:59:51.469100Z

Just out of interest - why (+ i 2)? Does ba store something unrelated at even indices?

pez 2021-03-02T21:15:13.469300Z

Yes, I am only interested in the odd indices. ba contains the results of an eratosthenes sieve, where I have skipped sieving even numbers, b/c we all know there’s only one even prime number. 😃

pez 2021-03-02T21:16:46.469500Z

I was hoping there was some reducer or something that would do all those steps for me.

p-himik 2021-03-02T21:19:10.469700Z

Oh, is that code just to find prime numbers up to n? If so, then even constructing the sieve could be made parallel. And I'm 95% certain there's already a Java library that does it. :)

pez 2021-03-02T21:19:36.469900Z

Haha, I’m in this to learn about Clojure. 😃

pez 2021-03-02T21:20:24.470100Z

That code is only to pick out the prime numbers I have found up to n.

pez 2021-03-02T21:21:49.470300Z

Here’s the full thing, using loop and transient:

(defn pez-ba-loop-transient-sieve [^long n]
  (let [primes (boolean-array (inc n) true)
        sqrt-n (int (Math/ceil (Math/sqrt n)))]
    (if (< n 2)
      '()
      (loop [p 3]
        (if (< sqrt-n p)
          (loop [res (transient [])
                 i 3]
            (if (<= i n)
              (recur (if (aget primes i)
                       (conj! res i)
                       res)
                     (+ i 2))
              (concat [2] (persistent! res))))
          (do
            (when (aget primes p)
              (loop [i (* p p)]
                (when (<= i n)
                  (aset primes i false)
                  (recur (+ i p p)))))
            (recur  (+ p 2))))))))

alexmiller 2021-03-02T21:22:40.471400Z

I’m not tracking this thread so please make sure relevant info ends up on the ask question, thanks!

pez 2021-03-02T21:23:42.471600Z

I haven’t ventured into how to speed up the sieving (beyond the obvious optimizations) b/c most of the time has been spent in picking out the indicies from the sieve.

seancorfield 2021-03-02T22:48:52.473800Z

We discourage cross-posting. People who want to see news and articles will subscribe to that channel. It's the same reason that articles/videos/etc are generally disallowed in #announcements -- it is for project/library releases only (and maintainers are discouraged from posting too often -- that's why we have #releases for more minor updates).

Timofey Sitnikov 2021-03-02T22:50:00.474100Z

OK, so how do you start? Do you just execute a single command and everything gets re-loaded?

seancorfield 2021-03-02T22:50:47.474300Z

FYI, every new member is automatically subscribed to #news-and-articles -- so if that channel has fewer people it is because they've chosen to leave it.

Felipe Reigosa 2021-03-02T22:50:59.474500Z

Got it. Sorry 😬

seancorfield 2021-03-02T22:51:41.474800Z

I deleted it from #clojure as it seems you are getting feedback in #news-and-articles

1👍
seancorfield 2021-03-02T22:52:10.475100Z

Sometimes you just need to be patient before people get around to responding 🙂

Felipe Reigosa 2021-03-02T22:54:01.475300Z

Maybe I got greedy, it's not like nobody cared, I'll stick to announcements from now on. 😀

devn 2021-03-02T22:58:18.475600Z

Thanks for the heads up @tcrawley — and glad it was sorted quickly.

p-himik 2021-03-02T22:59:13.475800Z

Nothing gets reloaded. You require t.d.a (tools.deps.alpha) and call the right function to add a dependency in runtime. The linked repo mentions this near the description of :add-libs: "see the example load-master function in the comments in my deps.edn". That example explains pretty much everything.

2021-03-02T23:21:16.484400Z

Hello Clojure friends. It's your prodigal son who's spent some time wandering in statically typed functional land, especially OCaml as of late. Compared to Clojure, OCaml's experience for live editing is really subpar, and I want to improve it. There are 2 routes I'm considering: 1. Add better REPL support in my editor (similar to Calva/CIDER) 2. Don't do a REPL per se, but instead do something like https://quokkajs.com/. Whereas a REPL is stateful, Quokka just runs a file and prints results inline in the editor, discarding the context each time. What do you guys think? I'm guessing that experienced Clojurians probably think 1 is strictly better than 2. Could you explain why?

vemv 2021-03-03T09:59:48.486700Z

Retrofitting a "real" repl into an existing language might be harder than it sounds. See https://news.ycombinator.com/item?id=25620256

2021-03-04T19:34:18.094700Z

the workflow that worked for me with OCaml was structuring my projects so that I could iteratively re-compile and run targetting the specific feature I was working on (kind of a TDD flow), since the OCaml compiler is extremely fast and its repl is significantly different from the compiler

2021-03-04T19:35:23.094900Z

with my OCaml projects I could compile to native code and run in less time than clojure typically takes to get a repl prompt

p-himik 2021-03-02T23:31:44.484800Z

One thing that immediately comes to mind - CPU intensive work. It wouldn't be fun to wait for something to finish each time you run the file or to keep track of all the temporary files with intermediate results. Another thing is side-effects. You usually don't want to repeat them unless necessary.

2021-03-02T23:34:05.485Z

Come to think of it, Quokka has some pretty crazy heuristics for finding exactly what code needs to be rerun to mitigate those issues @p-himik. Re implementing those for OCaml would not be fun, whereas with a REPL, the user decides what needs to be rerun.

Alys Brooks 2021-03-02T23:35:45.485200Z

I suspect a Quokka-style setup up is easier to get up and running since you don't have to maintain a connection so I don't know about strictly superior. Although if you're coming up with heuristics, it's probably not simpler anymore. Also, the reloading entire files avoids situations where, e.g., you're running (g (f val))) but the actual code running is (old-g (current-f val))) because you forgot to re-evalute your new definition of g.

p-himik 2021-03-02T23:36:30.485400Z

@d4hines Perhaps - apart from having a glance at the website, I'm not that familiar with Quokka so I was talking about just running a file each time.

Alys Brooks 2021-03-02T23:38:04.485600Z

I think the REPL approach is ultimately better because like you said, the user can decide and you can include shortcuts to reload the entire file. But running everything from scratch has a certain simplicity. I don't think it's well-suited to Clojure due to the startup time, but it might work for ClojureScript or something like Lumo or Babashka.