Fork me on GitHub
#clojure
<
2017-10-23
>
beoliver00:10:26

any ideas on why I get errors creating a ThreadPoolExecutor?

(def t-pool (new ThreadPoolExecutor (int 8) (int 2) (long 60) TimeUnit/SECONDS (new LinkedBlockingQueue 100)))
I just get
3. Unhandled clojure.lang.Compiler$CompilerException
   Error compiling form-init7780702103892101766.clj at (36:13)
2. Caused by java.lang.reflect.InvocationTargetException
   (No message)
1. Caused by java.lang.IllegalArgumentException
   (No message)
`

seancorfield02:10:53

@beoliver The second argument is maximumPoolSize so it must be at least as large as the corePoolSize (the first argument).

seancorfield02:10:16

I suspect you wanted (int 2) (int 8) instead?

mingp03:10:55

Hello #clojure. I'm curious for your opinion on something. What thing(s) in Clojure would you choose to show someone without prior exposure to the language to demonstrate as much upfront practical value as possible?

mingp03:10:05

Supposing your audience are experienced programmers familiar mostly with traditional imperative and object-oriented programming.

the2bears03:10:57

@mingp I think the first thing I would show would be REPL based development.

seancorfield03:10:45

Aye, the REPL can be very compelling -- especially if you show a live, running process and connect a REPL into it and explore and modify it while it's running.

seancorfield03:10:06

Depending on the background of your programming audience @mingp I think a demonstration of how easy it is to manipulate collections of data with map/filter/reduce. reducible-query in clojure.java.jdbc with a transducer pipeline, for example. Depending on the database and the configuration, you can stream very large record sets (that won't fit into memory) and still process them with transducers.

zentrope03:10:10

FWIW: What seemed to bowl over some devs I once knew was a single block of routes from compojure. The brevity got them interested.

taylor04:10:01

agree with showing something very practical. A lot of the really cool ideas in Clojure will likely be foreign at first and it might be hard to see the immediate value i.e. they don’t know what they’re missing. But everyone loves the “here’s how much boilerplate it takes to do the same thing in your lang” comparisons 🙂

zentrope04:10:03

Kind of a nice use case. Brevity. But also request/response as maps, thus highlighting the "it's all just data" idea.

bja04:10:05

For the working programmer, I usually demo the way clojure.java.jdbc allows integration of the Postgres geospatial and json queries and then add operators for json/geoquery using honeysql. I show "here's how you register serialization of these types to postgres, deserialization from postgres to my types, and this is how easy it is to query it with my custom operators. Put that together with compojure-api and I have a nice rest api console, validation for my endpoints, and arbitrarily complex SQL generated with very straight-forward functions (including demoing how easy transforms are when you have functions working with data). You can put it together on a couple pages and it's a real example that can be extended out in a useful way immediately.

bja04:10:33

I've mentioned this elsewhere, but I haven't found any language/ecosystem that is even close to as good at letting me clean data, generate complex SQL, and rapidly prototype well-documented apis. A lot of languages can let you build routes quickly, some even with beautiful documentation (django rest framework comes to mind with python). Almost every other solution gets insanely complex the minute I want to use database-specific features that invariably lead to string bashing.

zentrope04:10:16

A good exercise is to show the routes (say) and ask, 'Tell me what this code does' and see if they can get close.

zentrope04:10:51

The problem with a lot of Java frameworks (or even Django/Rails) is that it's super hard to figure things out without visiting dozens of files.

zentrope04:10:51

I imagine it's the same with SQL stuff (I just use the straight JDBC and strings).

zentrope04:10:13

In other words, it's not so much language nerd stuff, but all the get-it-done-fast so you can leave early stuff. And being able to figure out what others have done without also having to take anger management classes.

mingp06:10:04

Thanks all. Appreciate the ideas, and will give it some more thought.

reedho06:10:42

Hi, All. I'm fiddling with macros and and stumble with some behaviour which i think is strange.

(defmacro m1 [] (let [x (java.util.ArrayList.)] `~x))
(m1) ;; []
(type (m1)) ;; java.util.ArrayList

(defmacro m2 [] (let [x (org.joda.time.DateTime.)] `~x))
(m2) ;; #object[org.joda.time.DateTime 0x4011f484 "2017-10-23T13:05:15.179+07:00"]
(type (m2)) ;; CompilerException java.lang.RuntimeException: Can't embed object in code, maybe print-dup not defined: ...
Is it something related with reader take place in there?

keymone08:10:10

@reedho i think the problem is that there is no literal representation of DateTime

keymone08:10:33

(macroexpand-1 (m1)) <- this is the actual code that compiler is going to compile

keymone08:10:57

i really don’t know what should (macroexpand-1 (m2)) look like

keymone08:10:09

maybe you wanted your macro to spit out the actual (org.joda.time.DateTime.) ?

reedho09:10:38

@keymone actually i'm working with larger macro to provide some inlining, above is minimalist example in that i guess some reader take place with the above macro expansion

reedho09:10:16

It seems macro expanded values is serialized and then later need to be read again by reader

keymone09:10:36

yes, and org.joda.time.DateTime is missing the kind of serialization that makes reader understand it’s reading a literal for that class

reedho09:10:05

so, if it is something with reader, i wonder how [] can be brought back to java.util.ArrayList

reedho09:10:40

(type (read-string "[]")) ;; => clojure.lang.PersistentVector

keymone09:10:32

that is a good question

bronsa09:10:19

@reedho the problem is that you are embedding java objects in code, which is kind of a bad idea

reedho09:10:36

@bronsa actually it came from the clj-time.core/*

bronsa09:10:28

still kind of a bad idea :)

paulbutcher09:10:34

Can anyone point me in the direction of a good example of best practice for implementing migrations on top of DynamoDB?

reedho10:10:53

Regarding my question on macro above, actually the macro i'm trying to build is some thing like this:

(defmacro mk-route-check
  [routes]
  (let [dynamic-clauses
        (->> routes
             (mapcat
              (fn [{route :route
                    dows :dows}]
                [[
                  route
                  (if (= "DLY" dows)
                    '_
                    `(~'_ :guard
                      ~(->>
                        (clojure.string/replace-first dows #"^D" "")
                        (map (comp #(Long/parseLong %) str))
                        (into #{}))))
                  ]
                 true
                 ]
                )))]
    `(fn [route# dows#]
       (clojure.core.match/match
        [route# dows#]
        ~@dynamic-clauses
        :else false))))

reedho10:10:42

This is okay, inlining the routes

(mk-route-check
 [{:route "CGK-DPS" :dows "DLY"}
  {:route "CKG-MDC" :dows "D123"}])

reedho10:10:26

But i can not get it work if i want to load routes dynamically from somewhere, e.g.

(let [routes [{:route "CGK-DPS" :dows "DLY"}
              {:route "CKG-MDC" :dows "D123"}]]
  (mk-route-check routes))

bronsa10:10:51

you can't access run time values at compile time

reedho10:10:57

So, its means there is now way to make it works?

reedho10:10:10

I means, it can be made to work if i store the routes to root binding, and create macro based on that var

danm10:10:49

How does mk-route-check get called?

reedho10:10:02

But then i can not make seamless reloading mechanism by providing only function

reedho10:10:27

@carr0t some thing like:

(def __route-check nil)

(alter-var-root #'__route-check
                (constantly (mk-route-check
                             [{:route "CGK-DPS" :dows "DLY"}
                              {:route "CKG-MDC" :dows "D123"}])))

danm10:10:56

Macros run at compile time, so if you want to do something based on run-time variables your macro has to output forms which will do the right thing at run time

danm10:10:11

At which point the question may well be - why can't you just write a function instead of a macro?

reedho10:10:12

I need macro so that i can make core.match clauses from some external data

reedho10:10:23

I think like so 🙂

danm10:10:42

And that external data isn't available at runtime, it's only on the compile host? Can't it be in resources or something?

reedho10:10:18

Yes, it is actually some edn got read from resources

danm10:10:19

So why can't that be done at runtime?

reedho10:10:41

I want to achieve to e.g. provide simple function that could be used to reload the resource

reedho10:10:11

e.g. (reload-route-check "resource-file")

reedho10:10:11

then __route-check will refreshed with newest data

reedho10:10:20

implementation below doesn't work:

(defn reload-route-check [resource-file]
  (let [routes
        (-> resource-file
            
            
            (java.io.PushbackReader.)
            clojure.edn/read)]
    (alter-var-root #'__route-check
                    (constantly (mk-route-check routes)))))

yonatanel10:10:01

Is it bad form to query a db inside a map function if I need extra data for each item in collection? What are the alternatives?

reedho10:10:18

@yonatanel yes, one alternative is to change the query with JOIN clause if possible

paulbutcher11:10:46

I have, yes. And Ragtime and Joplin. I'm quite sure that all of these could work, but all of the examples are very SQL-focussed. I was hoping for some concrete experience/recommendations/best practice around DynamoDB 🙂

yonatanel11:10:59

@reedho What if my api is against some service that only answers one by one? Which iteration fn is appropriate when each item requires out-of-process data and might fail?

reedho11:10:58

@yonatanel for that case, i will prefer to use mapv

beoliver12:10:25

a little bit of macro help? trying to construct a function that has the form (f xs (g (f xs (g (f xs ...))))) I have the following

(defmacro m1 [pool n]
  (if (= n 1)
    `(ft ~pool "did not block")
    `(ft ~pool (ft-deref (m1 ~pool (dec ~n))))))
for 1 its ok, but for n>1 I can't get the recursion to work

qqq12:10:24

for writing complicated macros, I like to first write FUNCTIONS that do "list of symbols" -> "list of symbols" ... and then afterwards, have the macro call the function

qqq12:10:09

also, this particular macro looks like it can be written as a function of arguments f, g, xs

val_waeselynck12:10:09

(defmacro m1 [pool n]
  (if (= n 1)
    `(ft ~pool "did not block")
    `(ft ~pool (ft-deref (m1 ~pool ~(dec n))))))

val_waeselynck12:10:36

Curious to know why you'd want a macro for that though

beoliver12:10:18

@val_waeselynck I am playing with thread pools of (including ones of fixed sized)... if there are n threads and n+1 calls to deref then it will block. If I wrote it like this

(defn block-test [n pool]
  (loop [n n
         expr (ft pool "did not block")]
    (if (zero? n)
      expr
      (recur (dec n) (ft pool (ft-deref expr))))))
then each future is put on the thread pool straight away- so it does not block. I needed to construct an expression so that the calls weren't evaluated (perhaps I could just write the function the other way round?)

beoliver12:10:44

@val_waeselynck yeah I didn't need a macro

witek14:10:00

Hi. Ihave this: [:a :b :c]. How do i convert it into this: [[:a] [:b] [:c]]? Thank you!

dpsutton14:10:56

for each argument of your collection you want to call vector on the argument

witek14:10:26

So I have to use reduce? No simpler way?

taylor14:10:31

(mapv vector [:a :b :c])

taylor14:10:54

if you don’t need vector output, you could use map instead of mapv

uwo15:10:11

does Clojure not :import public static final fields from Java?

bronsa15:10:32

what do you mean

uwo15:10:41

nvm. figured it out

uwo15:10:26

actually I didn’t. is there a way to pull static final constants from a Java class into a Clojure namespace?

bronsa15:10:01

(def foo Klass/foo)

eggsyntax15:10:09

@bronsa that's a bit confusing -- there's not a way, or (def foo Klass/foo) is the way?

rarous15:10:37

you can’t pull static field directly in :import, you have to import class and then use (def foo Klass/foo)

eggsyntax15:10:42

NM, it was a colleague of mine looking for an answer, looks like he solved it.

bronsa15:10:32

@eggsyntax there's no way, but you can easily alias a static class field as a var using the above

eggsyntax15:10:49

Gotcha, that makes sense now. Thanks!

danm15:10:51

I have a question about sorted sequences - We have a large sequence/vector/set (multiple thousands of entries). We need it to be ordered, and we need to add to and remove from it. When we add we know the value of the thing we'd be sorting on (obviously), but when we remove we do not

danm15:10:57

How would you go about doing that 😉

danm15:10:15

Our initial naive version of a vector is hugely slow when we reconstruct it because we have to sort everything

danm15:10:42

A sorted set looked like it would work, but that converts to a regular set when we remove things from it

dpsutton15:10:48

> When we add we know the value of the thing we'd be sorting on (obviously), but when we remove we do not can you explain this more?

danm15:10:15

Basically, we're sorting on a timestamp

danm15:10:30

Each item also has an id

danm15:10:06

When we remove, we want to remove all things with id XXX (matching the thing we're about to insert) regardless of the timestamp they have

danm15:10:35

Or actually, we're sorting on timestamp and ID, because it is possible for 2 items with different IDs to have the same timestamp

dpsutton15:10:07

is it onerous to keep two copies of the collection?

dpsutton15:10:29

one hashed on ID, the other a binary tree by timestamp with collections of things at timestamp?

dpsutton15:10:50

look up by id , get timestamp, and then remove from binary tree?

danm15:10:33

That could work. It feels a bit nasty, but could work

dpsutton15:10:38

there's clojure.data.avl or something similar that would keep it balanced for you, not have to reinvint the wheel

joshkh16:10:13

storing transit data as jsonb in postgres - has anyone been burned by this?

tatut16:10:29

“… it should not yet be used for storing data durably over time…” says on the transit-format readme

tatut16:10:58

I’ve always heeded that warning

val_waeselynck16:10:34

@U0GC1C09L why use jsonb in this case? Once you have transit-encoded it, it seems to me the JSONB features of Postgres become useless (unless you rely on impl details of Transit), you might as well use a fressian-encoded BLOB

joshkh16:10:46

ah, good and valid point. thanks for being the voice of reason, @val_waeselynck

joshkh16:10:32

(and tatut!)

joshkh16:10:48

still figuring out slack Threads....

witek16:10:36

How do I create a map, in which the order is retained like in java.util.LinkedHashMap? I need vals to return the values in the order in which they were assoc'ed to the map...

witek16:10:50

I need it as .cljc

sundarj16:10:02

ah, sorry 😞

joshkh16:10:33

you could add a timestamp to the values and use a sorted map? https://clojuredocs.org/clojure.core/sorted-map-by

rauh16:10:49

@carr0t Do you need fast nth support on the sorted set? Or you just want to iterate it sorted by your values?

danm16:10:39

Well, we want to be able to periodically (like, every second) pull from it all events with timestamp < 'now', and push them onto our job queue

rauh16:10:29

So that means you'll be taking from the beginning until somewhere.

rauh16:10:59

Then this should fulfil your requirements: https://github.com/clojure/data.priority-map

beoliver16:10:05

A question about refs. Assuming that I have a data structure that I wish to share between multiple threads, but I want to both read and update in one single atomic action, do either of the following two examples capture this? I am unsure of the scope of dosync. As far as I am aware this (and refs in general) are used for atomic transactions using more than one state:

(def mah-data (ref [1 2 3 4 5]))

(defn mah-update-1 [data-ref]
  (dosync
   (when-let [a-value-that-no-other-thread-can-have (-> data-ref deref peek)]
     (alter data-ref pop)
     (println "value is" a-value-that-no-other-thread-can-have))))

(defn mah-update-1 [data-ref]
  (dosync
   (when-let [a-value-that-no-other-thread-can-have (-> data-ref deref peek)]
     (alter data-ref #(if (empty? %)
                        identity
                        (pop %)))
     (println "value is" a-value-that-no-other-thread-can-have))))

beoliver16:10:14

Intuitively I feel that I need to be requiring the lock before the deref, but I am not sure if this is the case using dosync

seancorfield16:10:42

If you only have one piece of state @beoliver you should be able to use atom and avoid dosync etc.

seancorfield16:10:06

ref is useful when you have two separate stateful things that you want to update together.

seancorfield16:10:17

(and, thus, ref is rarely needed or used)

rauh16:10:03

@beoliver You can use a "trick" like this

(let [state (atom [1 2 3])
      x (meta (swap! state
                     (fn [x]
                       (let [removed (peek x)]
                         (with-meta (pop x) {:rem removed})))))]
  [x @state])

beoliver16:10:17

@rauh is there any info on he trick? Is this the only way? If so, I am guessing that this must be an operation that is not considered idiomatic 😄

rauh16:10:41

@beoliver You don't have to, you can also avoid meta and just keep your "last removed item" in the state, but then whenever you want to use state you have to first get rid of the "last removed item"

rauh16:10:44

(let [state (atom [nil [1 2 3]])
      [lr] (swap! state (fn [[_ x]] [(peek x) (pop x)]))]
  [lr (second @state)])

beoliver16:10:25

would

(defn mah-update-3 [data-atom]
  (let [p (promise)]
    (swap! data-atom (fn [x] (deliver p (peek x)) (pop x)))
    (println "value is" @p)))
be considered a side effect?

rauh16:10:16

@beoliver That's not going to work

beoliver16:10:44

cant call it multiple times

rauh16:10:01

If swap! decides to re-run your fn, then your promise will still have the first (wrong) value

rauh16:10:21

You could certainly use another atom and reset that one. That'd work

Mudge20:10:52

the require function is not working within the proxy function. Does anybody know why?

ghadi20:10:27

gonna need a little more info to help @nick319

Mudge20:10:02

@ghadi thanks for your help. I am calling require to include a library within a function used by proxy

ghadi20:10:26

keep in mind require executes at runtime, not compile time... Stuff like this cannot work:

(let [...]
  (require 'foo.bar)
  (foo.bar/something...))

Mudge20:10:31

@ghadi here is a code snippet:

Mudge20:10:32

(proxy [VisionWindowListener] [] (windowOpened [win] (require '[clojuretest.windows.main-window :as script])

Mudge20:10:50

When I do that the library is not found

ghadi20:10:18

try to find a smaller error. Does running (require '[clojuretest.windows.main-window :as script]) work in your REPL?

Mudge20:10:32

I am wondering if it is because VisionWindowListener is using a different classloader than the library that I am trying to load

Mudge20:10:58

calling require right above proxy works. For example:

Mudge20:10:05

(proxy [VisionWindowListener] [] (windowOpened [win] (require '[clojuretest.windows.main-window :as script])

Mudge20:10:06

(require '[clojuretest.windows.main-window :as script])

Mudge20:10:27

(require '[clojuretest.windows.main-window :as script]) (proxy [VisionWindowListener] [] (windowOpened [win]

Mudge20:10:41

but I want to call require within a function defined in proxy

ghadi20:10:14

You only need to call require once at the top of your namespace, unless you are dynamically loading code

Mudge20:10:44

I understand. I am dynamically loading code, which is why I am calling it within a function that is within proxy

ghadi20:10:49

the example you're providing is not dynamic.

Mudge20:10:10

That is true, first I am trying to get a non-dynamic version working before I make it dynamic

ghadi20:10:44

So what are you going to do after you require the dynamic namespace?

Mudge20:10:15

then I am going to call function from the dynamic namespace

Mudge20:10:40

Does functions defined in proxy use the class loader of the interface that is being extended or is the classloader used the same one that clojure uses?

Mudge20:10:13

Because the interface I am implementing with proxy uses a different classloader than my clojure code

Mudge20:10:44

So I am wondering if that is the issue --- wondering if my proxy uses a different classloader than my regular code

ghadi20:10:58

what error are you getting

Mudge20:10:08

Is it legal to use require inside proxy function definitions? because everywhere else I use require, it works

Mudge20:10:14

I will get the error message

ghadi20:10:39

the problem is the scenario i described above

ghadi20:10:55

That will not compile ^

Mudge20:10:23

This is my error:

Mudge20:10:24

java.io.FileNotFoundException: Could not locate clojuretest/windows/main_window__init.class or clojuretest/windows/main_window.clj on classpath. Please check that namespaces with dashes use underscores in the Clojure file name. at clojure.lang.RT.load(RT.java:456) at clojure.lang.RT.load(RT.java:419) at clojure.core$load$fn__5677.invoke(core.clj:5893) at clojure.core$load.invokeStatic(core.clj:5892) at clojure.core$load.doInvoke(core.clj:5876) at clojure.lang.RestFn.invoke(RestFn.java:408) at clojure.core$load_one.invokeStatic(core.clj:5697) at clojure.core$load_one.invoke(core.clj:5692) at clojure.core$load_lib$fn__5626.invoke(core.clj:5737) at clojure.core$load_lib.invokeStatic(core.clj:5736) at clojure.core$load_lib.doInvoke(core.clj:5717) at clojure.lang.RestFn.applyTo(RestFn.java:142) at clojure.core$apply.invokeStatic(core.clj:648) at clojure.core$load_libs.invokeStatic(core.clj:5774) at clojure.core$load_libs.doInvoke(core.clj:5758) at clojure.lang.RestFn.applyTo(RestFn.java:137) at clojure.core$apply.invokeStatic(core.clj:648) at clojure.core$require.invokeStatic(core.clj:5796) at clojure.core$require.doInvoke(core.clj:5796) at clojure.lang.RestFn.invoke(RestFn.java:408) at clojuretest.core$create_window_listener$fn__13.invoke(core.clj:22) at clojuretest.core.proxy$java.lang.Object$VisionWindowListener$9dcff2dc.windowOpened(Unknown Source) at com.inductiveautomation.factorypmi.application.runtime.ClientContextImpl$1.windowOpened(ClientContextImpl.java:166) at com.inductiveautomation.factorypmi.application.FPMIApp.fireWindowEvent(FPMIApp.java:1197) at com.inductiveautomation.factorypmi.application.FPMIApp$InternalFrameEventRelay.internalFrameOpened(FPMIApp.java:1319) at javax.swing.JInternalFrame.fireInternalFrameEvent(Unknown Source) at javax.swing.JInternalFrame.show(Unknown Source) at java.awt.Component.show(Unknown Source) at java.awt.Component.setVisible(Unknown Source) at javax.swing.JComponent.setVisible(Unknown Source) at com.inductiveautomation.factorypmi.application.FPMIApp$RuntimeWindowOpener.openWindow(FPMIApp.java:1774) at com.inductiveautomation.factorypmi.application.FPMIApp.openWindow(FPMIApp.java:1014) at com.inductiveautomation.factorypmi.application.script.builtin.SecurityUtilities._tempReOpen(SecurityUtilities.java:230) at com.inductiveautomation.factorypmi.application.runtime.UpdateProjectPane.uninstall(UpdateProjectPane.java:103) at com.inductiveautomation.factorypmi.application.runtime.UpdateProjectPane$1.stepsFinished(UpdateProjectPane.java:91) at com.inductiveautomation.ignition.client.launch.AbstractStepRunner$1.run(AbstractStepRunner.java:40) at java.awt.event.InvocationEvent.dispatch(Unknown Source) at java.awt.EventQueue.dispatchEventImpl(Unknown Source) at java.awt.EventQueue.access$500(Unknown Source) at java.awt.EventQueue$3.run(Unknown Source) at java.awt.EventQueue$3.run(Unknown Source) at java.security.AccessController.doPrivileged(Native Method) at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source) at java.awt.EventQueue.dispatchEvent(Unknown Source) at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source) at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source) at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source) at java.awt.EventDispatchThread.pumpEvents(Unknown Source) at java.awt.EventDispatchThread.pumpEvents(Unknown Source) at java.awt.EventDispatchThread.run(Unknown Source)

ghadi20:10:24

because the compiler doesn't know what foo.bar/something is until the function runs...

ghadi20:10:35

(require 'clojuretest.windows.main-window :reload) does that work in a REPL?

Mudge20:10:15

I just tried it, yes

ghadi20:10:25

if you want to eliminate proxy from suspicion, you can move the body of the proxy method to an ordinary defn and try it there

Mudge20:10:52

I did that, it works in a regular defn

Mudge20:10:57

It just doesn't work under proxy

Mudge20:10:07

Also does not work under reify

Mudge20:10:53

I looked at your example:

Mudge20:10:54

(let [...] (require 'foo.bar) (foo.bar/something...))

Mudge20:10:02

Why can't that run at runtime and work?

noisesmith20:10:42

because the compiler errors if it can’t find foo.bar - you need a layer of indirection (eg. resolve) around the lookup of something to make that work

Mudge20:10:12

oh so if foo.bar is there then it will work

noisesmith20:10:23

if it’s required in your ns form

noisesmith20:10:48

or, if you already ran the code once so it already loaded it earlier…

ghadi20:10:24

this is affectionately called the "gilardi scenario"

ghadi21:10:26

a small example of require works fine in reify ... I'm wondering if something else is at play

ghadi21:10:58

(defn bar [] (reify clojure.lang.IReduceInit (reduce [_ f init] (require 'foo))))

;;; foo.clj
(ns foo)
(println "hey")

Mudge21:10:25

What if you try to reify an interface that uses a different classloader than clojure

Mudge21:10:19

In that code example you just gave does require use clojures classloader or does it use the interfaces classloader?

ghadi21:10:22

clojure's classloader -- sorry I can't work up a larger classloader example at the moment

Mudge22:10:08

@ghadi yes, but if clojure's class loader delegates to its parent class loader and if the parent class loader has the class then the parent class loader will then be used to load the classes in the class, and not clojure's class loader. I'm thinking that might be the problem. I am doing an experiment to find out.

nha22:10:01

I know we have https://github.com/clojure/test.check in clojure, which is great. Does the reverse exists? For example: I was trying to isolate an error in a biggish generated EDN/JSON structure. I have a unit test that fails with said structure with a given error. Would there be a way to remove parts of the structure to make is smaller to read, while keeping the same error? It seems it is a general debugging process I follow quite often (remove parts until it is small enough to understand it).

gfredericks23:10:33

@nha I haven't seen such a thing. I suppose it'd be theoretically possible to reuse test.check's shrink-loop if you wrote the code for doing the shrinking. but that's most of the work anyhow.

Mudge23:10:27

@ghadi I solved the problem with using require in proxy and reify

Mudge23:10:35

@ghadi The code that created the proxy object runs in a different thread than the code that calls the methods on the proxy. In the thread that calls the proxy methods the context classloader was not set to the classloader that has clojure. So simply setting the context classloader to clojure on the thread that calls the proxy methods fixed the problem. Thanks for looking into this with me.

tanzoniteblack23:10:49

@nha https://github.com/pjstadig/humane-test-output might be what you're looking for, but I don't have enough information about your particular situation to say for sure? If you have that loaded and try to compare to maps, then it will produce a diff if they don't equal each other.