Fork me on GitHub

When I eval (s/exercise-fn insert-cookie)` , it works, there are no errors. However, when I try to "fix" insert-cookie by changing :limit to ::limit at 38:7 , and try running exercise-fn again, I get this cryptic error:

; Error printing return value (NullPointerException) at java.util.Objects/requireNonNull (
; temporal
This is my code:


I just realised that the error lies not in exercise-fn but in my insert-cookie fn, there's something wrong with the (::limit options) cond branch body, but I cannot figure out what


@tahaahmedrasheedpk Given that you are passing in unqualified keys and your function deals with unqualified keys, I think your ::cookie-options spec needs :opt-un instead of :opt


Same with ::name-value-pair -- you're using :req which is for qualified keywords. You want :req-un.


I'm doing the opposite; I want to change the keywords in insert-cookie to their qualified variants


But when I try doing that I get the error


Show the code that actually errors then, so we can help (but I suspect I know what the error is).


When you change to ::limit you also need to change the destructuring on keys.


(let [{::keys [limit]} options] <-- so you get the :: version


Yep did that too


In you main ns, the :: auto-resolves to :main/ as a qualifier. Your destructuring can either be {::keys [limit]} as above or {:main/keys [limit]} or {:keys [main/limit]}


(defn insert-cookie
  [headers name value options]
   (cond-> ()
     (::limit options) (conj (let [{:keys [::limit]} options]
                               (if (integer? limit)
                                 (str "Max-Age=" limit)
                                 (str "Expires=" (.format DateTimeFormatter/RFC_1123_DATE_TIME limit)))))
     (::domain options) (conj (str "Domain=" (::domain options)))
     (::path options) (conj (str "Path=" (::path options)))
     (::secure options) (conj "Secure")
     (::httpOnly options) (conj "HttpOnly")
     (::sameSite options) (conj (::sameSite options))
     true (conj (str name "=" value)))
   (clojure.string/join "; ")
   (hash-map :name "Set-Cookie" :value)
   (conj headers)))
Here's what I have rn


No, that's not what I posted.


{::keys [limit]}


They're equivalent (I think)


Yeah, actually that does work -- I've never used that syntax (in ten years!) so I had to check in the REPL.


I think I found the problem, just a sec


When you exercise it, you get tagged output from ::limit so it is not valid input to insert-cookie (but you're not showing us code that would do that).


So what you're passing to do .format would be [:n 550000] (or [:t #inst ...])


So, the issue was that the inst? generator produced java.util.Date's (instead of java.time.instant's), which my function couldn't handle


Here's the fixed code:

(defn insert-cookie
  [headers name value options]
   (cond-> ()
     (::limit options) (conj (let [{:keys [::limit]} options]
                               (if (integer? limit)
                                 (str "Max-Age=" limit)
                                   (instance? java.util.Date limit) (.toInstant)
                                   true (.format (.withZone
                                                  (ZoneId/of "GMT")))
                                   true (str "Expires=")))))
     (::domain options) (conj (str "Domain=" (::domain options)))
     (::path options) (conj (str "Path=" (::path options)))
     (::secure options) (conj "Secure")
     (::httpOnly options) (conj "HttpOnly")
     (::sameSite options) (conj (::sameSite options))
     true (conj (str name "=" value)))
   (clojure.string/join "; ")
   (hash-map ::name "Set-Cookie" ::value)
   (conj headers)))


Oh, wow, that was a subtle one... yeah, I hadn't even noticed that... Dates are hard 😞 I'd love everything to be Java Time but the reality is a nightmare mix of java.util.Date (and the java.sql.* variants) and Java Time and sometimes Joda Time 😞


Hi @tahaahmedrasheedpk - been scanning through here. re:java.time and libraries, not sure if anyone's mentioned, which provides literals for java.time - e.g.

#time/instant "2018-07-25T07:10:05.861Z"
also, I think sticking to the java.time api (rather than a wrapper) is a good idea especially if you're just learning it, but IMO gives a better experience of that

👍 1
Jim Newton09:10:47

I worked for several hours trying to figure out why a very simple function was not returning the same thing within the program as I get at the repl. I had trouble sleeping because it didn't make sense. Today when I restarted the program it worked perfectly. I think one of my memoized functions what not being called. but some other function (not the memoized ones, but one which it calls) had been edited after the value was memoized. What's the lesson learned?

👍 3
Jim Newton10:10:39

I have a collection of data structures all of the same Record with several keyword fields. Some of the records are accessed seldomly. There is a particular field whose value is expensive to compute. I'd like to compute it only the first time it is needed, if at all. Thereafter, I'd like that value used for subsequent accesses to the field. Is there some mechanism for this? Or do I need to invent this myself?


@jimka.issy as already answered, delay can be used, but memoize is also particularly handy for caching function results

Jim Newton11:10:43

Can memoize be used for caching local function results?


@jimka.issy Yes, (let [f (fn [x] x) f (memoize f)] ...)

Jim Newton13:10:47

does the cache prevent the local function from getting GC'ed ?


not really, since the state of that function is also local. but note that arguments that are used for memoization will be stored in an atom, so as long the memoized function lives, the arguments don't get GC-ed


this actually bit me in clj-kondo since I had a global memoized function, so all the args that were passed to it, lived forever


Are there any examples out there that integrate a clojure backend with AWS Cognito? My searches didn't bring anything up

Matias Francisco Hernandez Arellano12:10:42

Hi folks.. is it possible (i know it is but not sure how) have a plugin/drop-in architecture?: Mi idea is to be able to add a command to my bot by just adding the corresponding files into the corresponding namespace under discord-bot.commands where the command have to at least implent the handler function. Then "somehow" (this is the tricky part) import all of the discord-bot.commands.* into the core and call the handler function of each one.


I think I did something similar a while ago. It involved using to get the relevant namespaces. From there, use to get the var holding each handler fn. Then call it 🙂

👍 1
Matias Francisco Hernandez Arellano20:10:07

Thanks Folks will check that

Matias Francisco Hernandez Arellano12:10:50

How can that import be implemented?


Do you want the import happen at compile time or while the application is running?

Daniel Stephens13:10:44

Does anyone know if there is either a way to make IntelliJ Cursive not format comments, or make cljfmt format comments? We have cljfmt as our formatter shared across the team, Cursive format seems slightly different but normally if it changes something it gets undone when I run cljfmt. Unfortunately Curisve also likes formatting comments and cljfmt doesn't touch these meaning any changes the Cursive formatter makes, sticks and causes a lot of noise in PRs.

João Galrito16:10:32

I have a thread running in the background that takes in 2 inputs from a queue and produces an output. Is there any way that I can store the latest inputs/outputs somewhere and print them in the repl when I want to check what it's doing?

João Galrito16:10:58

I've tried an atom but it just blocks


atoms never block


can you post an example of your code @joao.galrito?

João Galrito16:10:16

i suppose its the main thread that's blocking

João Galrito16:10:28

yea it was the main thread that was blocking, because I was running the function directly from the REPL

João Galrito16:10:44

if i do (thread (my-fn)) now I can read the atom in the REPL


hi, I need to subtract 3 hours from a date, may someone can help?

(t/minus (java.util.Date.) (t/hours 3))


Got you with the ultimate clojure date hack.


(let [le-now (.format (java.text.SimpleDateFormat. "yyyyMMddHHmmss") (new java.util.Date)) n-hours-ago (.format (java.text.SimpleDateFormat. "yyyyMMddHHmmss") (new java.util.Date (- (System/currentTimeMillis) (* 3 60 60 1000))))] (println "now: " le-now) (println "3 hrs ago: " n-hours-ago))

👍 1
🎉 1
João Galrito16:10:52

maybe use Calendar?

João Galrito16:10:31

(doto (Calendar/getInstance) (.add Calendar/WEEK_OF_YEAR -2))


don’t use either java.util.Date or java.util.Calendar unless you have to for legacy reasons, new code should use java.time


(-> (Instant/now) (.minus 3 ChronoUnit/HOURS))

João Galrito17:10:01

sucks that you can't add/subtract months with java.time though


you can, you need to use LocalDateTime or ZonedDateTime instead of Instant

👍 2
Michael Stokley19:10:13

i thought the current best practice was to use java.time


I got this serialized json array a:3:{s:1:"a";i:1;s:1:"b";i:2;s:1:"c";i:3;} how would I parse this in Clojure?


@slack.jcpsantiago are you getting that from a PHP/Laravel API?


doesn't look like json.. is it bencode?


I’m pretty sure I came across that when writing an integration with an API implemented in PHP.


that format, I mean


it’s possible, I got it from a CSV file in which one column has these serialized arrays. I think it’s PHP but I’m not sure