Fork me on GitHub

Is the clojure.inspector namespace not bundled with Clojure 1.10.1?

(clojure.inspector/inspect "foo")
Execution error (ClassNotFoundException) at (


Or maybe it’s a post-Java-8 thing… :thinking_face:


Hmm, no, project settings are using the 1.8 JVM.


(require 'clojure.inspector)


do that first?


Aha, that works. Should’ve thought of that myself.




I had project.clj on my mind.


In CLA with Subject 3. “With respect to any patent you own…” Can someone explain me that phrase ?


Anyone that who signed this can explain this to us ?


IANAL, so you cannot take this as legal advice, but I believe the intent there is "if you have a patent, or a license to use a patent, you agree to let us license that patent when we want to use or copy or sublicense your code contribution.


From Rich's side, hopefully you can understand it would be bad if someone contributed some code to be included in Clojure, or a contrib library, Rich accepted it into Clojure, and then later the contributor said "Oh, by the way, you owe me licensing fees for patent X that I own, because of my contribution you took."


I don’t want any money from my contrubution, or I will never will. But, I want to protect my future patents from this point-of-view…


Understood, and you are correct to be cautious. Again, I am not a lawyer, but the language there seems to be worded such that only patents you have that are related to code you contributed under this agreement are relevant. If you have patents that are unrelated to your code contributions, no license is given for those.

😇 4

Code submitted in this agreement can be copied, sold, sublicensed, etc. is the permission given. It does not say "you agree to let us use every patent you own"


@U0CMVHBL2, The patents I will have aside from Clojure or Clojurescript. I mean, I know my contribution will all yours. And I’m happy with that. This community was always nice to me.


But I will have patents in my future. Maybe more than one-or-two.


Is this Agreement includes all of my patents aside from this open-source projects ?


In the USA at least, if you publish an idea, and wait more than a year, you can no longer patent it. So if you contribute code that uses a patented idea, either you already have the patent, or you have just started a 1 year clock for not being able to patent it any more.


I’m from Turkey. 😂


If you are really concerned about this, you should hire an intellectual property lawyer. My reading of the language is "you license any patents to us that we would need in order to use your code contribution", NOT "you license all patents you own to us"

scknkkrer18:07:04;cid=C03S1KBA2 This message explains a lot. If my patent is not about my contribution, then, they are not included with this agreement.


@U0CMVHBL2, right ? :face_with_rolling_eyes:


And, @U0CMVHBL2,have you accepted this licence ?

Alex Miller (Clojure team)18:07:22

just to going back to clarify what you said above, you said "I mean, I know my contribution will all [be] yours." but actually that's not true - it is a joint ownership. You retain ownership on the contribution but also grant that ownership independently to Rich Hickey.

Alex Miller (Clojure team)18:07:46

Re "Is this Agreement includes all of my patents aside from this open-source projects ?" the answer is no.

Alex Miller (Clojure team)18:07:08

It says in the first sentence that this "applies to any contribution that you make to any product or project managed by us" and 1. lays out what that means in detail ("source code, ...").

Alex Miller (Clojure team)18:07:44

that is the scope of the agreement, and it does not extend to other things that you are not contributing


I have accepted that license, about 10 years ago. I have filed and been granted patents in that time that are unrelated to my Clojure code contributions.

Alex Miller (Clojure team)18:07:43

#3 is a patent protection clause saying that if you do have a patent on your contribution, you grant license to Rich to use it. you retain the patent. it does not apply to any patents that cover things outside the contribution.

Alex Miller (Clojure team)18:07:16

and standard caveat - I am not a lawyer, you should seek your own legal advice. this is my non-official interpretation.


I’m not seeking any legal advice. I know this community is like a family. But my bad English leads me to this big question. “I will have patents that are unrelated to my Clojure/Clojurescript contribution; and then they patents are under share ?” Thank you guys.


No they won't be (again, IANAL)

Graham Seyffert17:07:59

While I’m still trying to nail down a reliably reproducible case, I’d like to give @ghadi a big shout out for helping me figure out a working fix a classloader issue we were seeing on JDK 11 but not JDK 8. The main issue appears to be leting a record field in one thread, and then trying to access that field in a bound-fn (TBD whether bound-fn has an effect, but @ghadi’s theory is that it may convey a different classloader to the child thread than what’s in the parent thread) that runs in a Fork/Join pool thread via reducers.fold. In some circumstances (still TBD exactly which circumstances…), trying to access this field in a child thread would result in a java.lang.NoClassDefFoundError. This seems to be related to AOT compilation, and rolling back to JDK 8 from JDK 11 would reliably fix the issue. One thing to note here is that these records are instantiated at runtime as a workaround for this issue - Unfortunately, I’ve only been able to get this error to reproduce in our QA environments, and attempts to reproduce locally first with our main project, then in my REPL, and finally with a “minimally-reproducible” project I’ve set up have proven fruitless 😢 if anyone else runs into this issue in the future, I’d love to hear from you and try to narrow down exactly why this error might occur. The current fix is to capture the classloader of the parent thread in a dynamic var, and then within our bound-fn set the classloader of that thread explicitly. I’d like for us to not have to do this manually, but this fix unblocks us at the moment and definitely works! Additional information: - Mixed Java/Clojure project (significantly more Java than Clojure) - AOT compilation via clojure-maven-plugin:1.8.1 - Compiling on JDK 8 and running on JDK 11 (this is a requirement for us for the time being) - Patched version of Clojure 1.10.1 with the fix for applied Again, big props to @ghadi here for helping identify what was happening and suggesting a way to fix it. Example block of code that produces this error -

(defn my-fn
  [a-coll a-record]
  (let [a-fn (:some-kw a-record)
        reduce-fn (bound-fn
                    ([] {})
                    ([m itm]
                     (if (or (nil? a-fn)
                             (a-fn some args)) ;; throws here
  (fold 4 merge reduce-fn a-coll))


it seems transit could also cache values instead of only keys: I have a lot of values that are the same, only sometimes not


yeah - I've verified that transit caches arbitrary values within one payload - probably key reusage is more common, but for structures that have repeating subtrees it will cache them


Then why do I see the same filename string over and over?


oh weird - I didn't notice that


Watch this:

$ echo '[{:a :abcabc} {:a :abcabc} {:a :abcabc}]' | jet --from edn --to transit
[["^ ","~:a","~:abcabc"],["^ ","~:a","^0"],["^ ","~:a","^0"]]

$ echo '[{:a "abcabc"} {:a "abcabc"} {:a "abcabc"}]' | jet --from edn --to transit
[["^ ","~:a","abcabc"],["^ ","~:a","abcabc"],["^ ","~:a","abcabc"]]


so it seems transit only caches keywords?


try it with identical? and not just equal? input? I thought I saw it compress... maybe I'm misremembering


Does anyone with experience in neo4j-clj.core wanna help me understand queries?


Hi, will try to remember to answer your question tomorrow (at work).




Hi @amiller68, I think @gseyffert already answered your question. You might want to have a look at the explanation at the Neo4j Cypher Manual, section Parameters: There you can see that $param is recommended over {param}, and all the nesting stuff.


I'm trying to understand what exactly gets passed to a query using the $ syntax

Graham Seyffert18:07:35

@amiller68 $ syntax defines a query param for your query. So if you have $myField, it would expect you to pass a map like {:myField "foo"} when you want to execute the query


I'm a programming language person that has been using Clojure for a bit of time now. I love the language, yet I don't really think I understand the semantics (i.e. what is really happening when I define a var or evaluate some S-expr). Can anyone point me in the right direction?

Alex Miller (Clojure team)18:07:47

there is no specification for Clojure

Alex Miller (Clojure team)18:07:56

the closest thing are the reference pages on


@alexmiller you seem to always know what is going on. is this because you took a look at the compiler?

Alex Miller (Clojure team)18:07:52

I work on the Clojure team

Alex Miller (Clojure team)18:07:00

so, yes I have worked on the compiler :)


Lol I guess I shouldn't compare my understanding to yours then


Thank you though. I guess I will have to take a dive into the code at some point.

Alex Miller (Clojure team)19:07:25

well, I wouldn't make that the first stop. there are plenty of decent books that are more approachable than the compiler

Alex Miller (Clojure team)19:07:36

in a nutshell, namespaces contain mappings from symbols to vars. vars are stateful boxes which hold a value. when you (def x 5), the result is that in the current namespace (say user), a mapping is created from the symbol user/x to a Var that holds the value 5.

Alex Miller (Clojure team)19:07:15

for evaluation, you can get pretty far with these 3 rules: 1. most things evaluate to themselves 2. symbols are evaluated by looking up their value in a namespace (the user/x above is looked up and evaluated to 5) 3. lists evaluate each element, then invoke the first element with the rest as args

Alex Miller (Clojure team)19:07:19

it's a list, so evaluate it's args

Alex Miller (Clojure team)19:07:43

+ is a symbol, so look it up - clojure.core/+ is a var whose value is a function object

Alex Miller (Clojure team)19:07:02

x is a symbol, so look it up - user/x is 5

Alex Miller (Clojure team)19:07:17

so then you have (<+ function> 3 5)

Alex Miller (Clojure team)19:07:31

invoke the function object with args (3 5)

Alex Miller (Clojure team)19:07:58

Macros take a bit of a detour. In #3, if the first element refers to a macro, don't evaluate the elements, instead invoke the macro with the unevaluated elements. replace the original form with what you get back, and start over.

Alex Miller (Clojure team)19:07:22

that's 98% of what you need to know to understand Clojure evaluation

😎 8

@alexmiller if a macro replaces with another macro does the process repeat until we reach a "normal" form


TL;DR: Clojure's semantics are much simpler than other mainstream languages 🙂


I've been using these rules without knowing it for quite some time


I'm glad it's so simple

Alex Miller (Clojure team)19:07:40

I guess I didn't mention the reader and quoting, so this is maybe actually only 90% of what you need to know :)

Alex Miller (Clojure team)19:07:58

I'll be teaching the intro class before Clojure/conj if you want the long version :)


@alexmiller I feel that I know the language pretty well - I've written a lot of code at the very least. So maybe the class will be too simple.


I do very much appreciate your explanation of evaluation. I'm very curious about interning/reader/quoting so I'll explore those next.

Alex Miller (Clojure team)19:07:18

it's covered in the link above


why doesn't transit cache string values?

$ echo '[{:a :abcabc} {:a :abcabc} {:a :abcabc}]' | jet --from edn --to transit
[["^ ","~:a","~:abcabc"],["^ ","~:a","^0"],["^ ","~:a","^0"]]

$ echo '[{:a "abcabc"} {:a "abcabc"} {:a "abcabc"}]' | jet --from edn --to transit
[["^ ","~:a","abcabc"],["^ ","~:a","abcabc"],["^ ","~:a","abcabc"]]

Alex Miller (Clojure team)20:07:45

I was not around for the design of this, so I don't have any authoritative knowledge. but strings are of arbitrary size and quantity. having a cache with a low hit rate is memory expensive on write, so seems like it may not be the best choice.


it makes sense from that perspective yes, especially if transit only does one pass to determine caching

Alex Miller (Clojure team)20:07:06

it's streaming, so that's necessarily true

Alex Miller (Clojure team)20:07:49

map keys are quite commonly reused and of limited size


transit does cache string keys (which also makes sense)


$ echo '[{"abcd": 1}, {"abcd": 2}]' | jet --from json --to transit
["~#list",[["^ ","abcd",1],["^ ","^1",2]]]


Hi all - question for the group: I've been trying to understand how reagent components subscribe themselves to ratoms, however attempting to read the source was a little beyond my reach. I've currently been unable to find any blogs/articles that focus specifically on explaining this narrow component (heh) of reagent. Would anybody be able to either point me to a reference or help me understand how exactly this works under the covers? I initially thought that reagent must do some sort of codewalking of each component and look for a deref, then save itself to the ratom, but from the little I could understand of the source, it seems that it has to do with setting a dynamic var containing ratom context which can be accessed during the render function anywhere in the callstack, but the details are murky to me.


the deref call on the r/atom inside the data literal registers the containing structure for re-render


the relevant code is in r/atom deref iirc


yah i looked there, it wasn't immediately clear to me but that's probably just lack of experience


i think that's pushing the updates, but not the subscribing part


no, because attaching an update to a read is nonsensical


it's registering the rendering block for future updates


(if (nil? c)
        (set! (.-captured r) (array derefed))
        (.push c derefed)))))


right, that's adding the context of the deref to the list of things to render, if I read it correctly


there is a little more going on that i need to undertand but that's the right place


I assume that c is an array, and the push method extends it


ratom-context is where the captured component seems to be placed


it is, but it c omes from the dynamic context - i didn't paste the whole snippet but for posterity's sake:

(defn- notify-deref-watcher!
  "Add `derefed` to the `captured` field of `*ratom-context*`.
  See also `in-context`"
  (when-some [r *ratom-context*]
    (let [c (.-captured r)]
      (if (nil? c)
        (set! (.-captured r) (array derefed))
        (.push c derefed)))))


and c is the .-captured of *ratom-context*, right


just need to figure out how ratom-context plays in with everything and I think i'll have a decent grasp


it's pretty cool how this works


it's interesting / strange that the deref method on RAtom puts itself into the watcher - so the rendering object is attached elsewhere


exactly - and why i've been a little stuck while sifting through this


basically i was trying to right a very simplified version of a component registering itself for kicks


I always like to try toy implementations of the big ideas in libraries, good for learning and also fun


but i got a little stuck on this one


thanks - yeah i see that, I think I've got some more digging to do 🙂


I know where the pieces are, now just need to synthesize them


Hi @amiller68, I think @gseyffert already answered your question. You might want to have a look at the explanation at the Neo4j Cypher Manual, section Parameters: There you can see that $param is recommended over {param}, and all the nesting stuff.