Fork me on GitHub

Hi, I am trying to write a test for this function:

(defn find-copyright-statements-in-file
  "Find copyright statements in the given file"
  (let [re #".*[Cc]opyright.*(19|20)[0-9][0-9].*"]
    (with-open [r (io/reader file)]
      (remove nil? (map first (map (partial re-find re) (line-seq r)))))))
I have this in my test:
(deftest test-find-copyright-statements-in-file
  (let [output (c/find-copyright-statements-in-file file)]
    (is (= (count output) 1))
    (is (= (first output) expected))))
This gives me an error:
ERROR in (test-find-copyright-statements-in-file) (
expected: (= (count output) 1)
  actual: .IOException: Stream closed
 at .BufferedReader.ensureOpen (
    .BufferedReader.readLine (
    .BufferedReader.readLine (
I was playing around in the REPL... I found that if I do (def x (find-copyright-statements-in-file some-file)) then I can do things like x, (count x), (first x) and they work fine, but if I try to do it in a let instead of a def I get these same errors - e.g.
(let [y (find-copyright-statements-in-file file)]
  (print (count y))
  (print (first y)))
Execution error (IOException) at .BufferedReader/ensureOpen (
Stream closed
class .IOException
I do not understand why it works in the def but not in the let. I assume it has something to do with then the lazy seq is actually evaluated... any help appreciated! Thanks in advance


Oh - answering my own question - I guess typing it out suggested the answer.... I change the function to this

(defn find-copyright-statements-in-file
  "Find copyright statements in the given file"
  (let [re #".*[Cc]opyright.*(19|20)[0-9][0-9].*"]
    (with-open [r (io/reader file)]
      (doall (remove nil? (map first (map (partial re-find re) (line-seq r))))))))
Now it works like I expected 🙂

duckie 12

BTW I hink you can replace (remove nil? (map ...) with keep Also take a look at transducers. You can put together all the mapping functions by calling them without the collection argument, then you can use that xf with into instead of doall, because it is eager when used with a transducer. It may give you some performance gain.


Without the doall, the rest of the functions you are using there are lazy, which prevents them from being evaluated within the scope of the with-open, and if you try to force the lazy sequence after leaving the scope of the with-open, the file is closed and gives an error.

💯 4

Hello there! Anyone using Datomic in production? How much space will it accumulate over time? I mean, we don’t lose data, which is a pretty fancy cool thing, but what about when I don’t have more space? Are there some functions to reset the database every month for example. So the state one month ago will be the “first state” of the database?


#datomic is the place for this


But you can decant the database into a new one


If you're planning on putting that much data into datomic, you might struggle. There's a soft limit on the data you can put in, and you'll need to speak with cognitect for capacity planning.

Nima G14:12:25

Is Gradle the way to go if I want to write both Java and Clojure in a project?


I would first look at Maven for that.


Also consider Leiningen, in particular in combination with

Nima G14:12:31

Thanks for the replies. I actually didn't know about java-source-paths in leiningen


Yeah. If you're already using leiningen, I'd just go that route ^^^

👍 4

When AOT-ing a project with JDK 11 and deploying it to clojars, will the project be able to run with JDK 8? I may have accidentally done that


Whether a .class file works on certain JDK version depends on the bytecode version that .class files have. says that clojure 1.10 generates Java 8 bytecode.


ah, so if I don't use any fancy java 11 features, chances are it still works?


It won’t work if you used parts of JDK libraries that are in JDK 9 or later. Otherwise it could work.


and is there a way to check which java version has been used for a specific artifact?

Alex Miller (Clojure team)17:12:11

If you have class files, javap can tell you which version they are


bug or feature?

(defn var
  ([name] (var name nil nil)) ;;=> always returns #'clojure.core/name
  ([name init-val] (var name init-val nil ))
  ([name init-val meta] (SciVar. init-val name meta)))
Probably using var as a function name in a public API (or at all) is not a very good idea


I don't think special forms can be shadowed


Or it seems they can, but not if they're the first element of a form


I had a similar issue recently


I don't know if that's correct or not, but I like to think of them as read time macros


Like they get evaluated at read time, even before macro-expansion


Hum... well ya that doesn't seem to be the case. But oh well. I'm not too sure what the semantics are for special forms and when they are processed exactly. But I'd avoid shadowing them 😝


It seems like a thing a linter one might want to warn about 🙂

❤️ 4

I don't think Eastwood does so.


hm yeah.. 🙂


I think they're processed directly by the compiler. And depending which special form it is, they'll have the compiler do something different. But in the context where you shadowed a special form. I guess you could consider it a bug that the compiler misidentifies the code as a special form when it isn't referring to one. At the same time, I don't know if it's possible (or just way too hard) to detect the difference.


I have this inside a clojure interpreter:

;; derived from (keys (. clojure.lang.Compiler specials))
;; (& monitor-exit case* try reify* finally loop* do letfn* if clojure.core/import* new deftype* let* fn* recur set! . var quote catch throw monitor-enter def)
(def special-syms '#{try finally do if new recur quote catch throw def . var set!})


I mean, just imagine the confusion that one could create by trying to name a function .


so I guess the same will happen when you call a function throw


I had fun debugging Eastwood running on a Clojure library that defined, I believe, a macro named catch


(def def (fn [] "lol"))


which I believe worked as the authors intended it to.


user=> (def throw [])
user=> (throw)
Syntax error compiling throw at (REPL:1:1).
Too few arguments to throw, throw expects a single Throwable instance


I think it does work


user=> (defn catch [])
user=> (catch)


Just need to fully qualify your fn name namespace/var


catch probably works because that symbol only has a special meaning inside throw


something like that, yeah.


@U0K064KQV it could work with a namespace prefix, but what if the function is recursive like in my original post?


aaaanyway, good to lint


`(def def (fn [] "lol"))
(def) ; too few args to def
(def a 10) ; #'a
a ; 10
(user/def) ; lol`


It does not come up very often in live code examples, but there might be something out there.


oh yes, this works:

user=> (defn var ([x] (user/var x nil)) ([x y] [x y]))
user=> (user/var 1)
[1 nil]


still probably good to avoid. I bet I will trip some edge case in CLJS or something when I go ahead with this


Ya. I also don't really understand the underlying mechanism. I guess the compiler probably just first checks if the symbol in first position is a special form, if so treats it as one. If not, performs var resolution in the given namespace. And when the symbol is fully qualified, it does not equal any special form so that probably works.


Seems to work in CLJS as well. But ya, who knows what other edge case it could have.


i don't know if the details are still accurate but there is a bit in the "clojure for java programmers" (part 1) rich hickey talk that mentions about the order -- around 1:03:00 or so (the op slide)


Yes, although that might be a somewhat simplified explanation vs. what the compiler actually does, even at the time that talk was given.


The details of name conflicts can get pretty finicky here, I suspect.


i hope to some day understand it well :)


Eh, if you get insanely curious, I would recommend adding several System.out.println calls into likely-looking places in the Clojure compiler implementation, then come up with several example forms to compile and evaluate that should exhibit different behaviors in that area. It can be time consuming, but on the order of hours, not weeks.


well, perhaps hours stretching into days 🙂


thanks for the tips -- may be my curiosity level will reach that point before long


anyone know of any efforts to use Clojure as a macroassembler for systemverilog?


it's something I've been thinking of quite a bit recently, given past experience using Clojure for DSLs/compilers and a new work focus on SV


is it bad practice to shadow a variable via a let binding that's out of scope?


granted not a core clojure function


Not sure what you mean by "that's out of scope" there. Do you have an example of what you mean?


I mean, how can you shadow something unless it is visible in the scope of where the let expression is?


for example, I often use key destructuring, but if I need to process a key before passing it thoruhg, I often shadow

(let [{:keys [a b c]} some-obj
      a (if (= b 2) a 0)],,,)


sorry, you're right, not out of scope


In a small enough let, I would think the meaning is pretty clear to all all slightly experienced Clojure developers.


The larger the let gets, the harder everything is to follow, not just shadowing.

💯 4

I often do a' or something, but evil-cleverparens has some annoyances with stray single-quotes


I am not familiar with evil-cleverparens, but if that is intended to be a Clojure or Lisp-specific mode, it might be advisable to report that and see if they can improve on it.


I think so.


i wouldn’t read into that too much. may just mean many clojurians are happily employed, effective in small numbers, and anti-hype 😛


Don't know what to say... Clojure is amazing, but the battle for mindshare is tough, and Clojure puts little focus on it and doesn't really care. Or should I say, wouldn't compromise its goals to make itself more attractive, for good reasons.

Alex Miller (Clojure team)23:12:41

Those are based on very small percentage differences at one online job site

Alex Miller (Clojure team)23:12:17

My impression is that there are more companies hiring more people now than ever

Alex Miller (Clojure team)23:12:22

Was just at Clojure Conj, full of people at companies hiring Clojure devs

💯 24

That's good to hear.


I wonder what's the threshold for being included on that list. I can imagine the job postings mentioning clojure went from 5 to 1, just by chance of the measuring date.


It's kind of weird to see Clojure (a relatively new and popular technology) among other dinosaurs like jsp, solaris (!), vba, flash, windows XP (!!) ...


I don't necessarily pay too much attention to such reports but I still find it peculiar that among all possibile niche technologies that exist and are declining it's Clojure has the taken first position.


Compared to flash it was particularly surprising for me as well. That suggests, according to the worlds largest jobhunting site, that more people are interested in sticking with flash for their work than clojure?


Maybe that's because there are few corporate jobs and companies are simply no longer posting their positions on that website anymore. Maybe most recruitment these days happens in other forms (other hiring platforms, this slack's channels, conferences ect).


But it could be as well just an anomaly in the way they processed their data. I doubt that people are sticking more with Flash than with Clojure.


Also I remember that in the past many backend -positions would list Clojure as a "nice-to-have" technology in their description. Maybe it's no longer the case nowadays and this highly influenced the final result.