This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-09-20
Channels
- # announcements (3)
- # babashka (7)
- # beginners (43)
- # biff (19)
- # calva (39)
- # cider (16)
- # clerk (2)
- # clj-yaml (32)
- # cljs-dev (37)
- # clojure (129)
- # clojure-australia (1)
- # clojure-china (1)
- # clojure-europe (46)
- # clojure-filipino (1)
- # clojure-gamedev (25)
- # clojure-hk (1)
- # clojure-indonesia (1)
- # clojure-japan (2)
- # clojure-korea (1)
- # clojure-my (1)
- # clojure-nl (5)
- # clojure-norway (8)
- # clojure-sg (1)
- # clojure-sweden (12)
- # clojure-taiwan (1)
- # clojure-uk (9)
- # clojurescript (14)
- # core-typed (136)
- # cursive (18)
- # duct (9)
- # emacs (12)
- # etaoin (7)
- # events (1)
- # graalvm (3)
- # gratitude (2)
- # humbleui (7)
- # hyperfiddle (99)
- # introduce-yourself (5)
- # jobs (2)
- # leiningen (1)
- # missionary (14)
- # nrepl (2)
- # off-topic (12)
- # polylith (21)
- # rdf (29)
- # re-frame (8)
- # releases (1)
- # shadow-cljs (264)
- # spacemacs (21)
- # sql (7)
- # vscode (1)
Hi all. I am getting an "Attempting to call unbound fn" error on this code running in a JAR (it runs fine in dev):
(defn handle-ws-connection [req]
(let [doc-uuid (uuid-from-ws-req req)]
(hk-server/as-channel ...more code... )))
(defmethod ig/init-key :adapter/ws-http-handler [_ {:keys [handler] :as opts}]
(hk-server/run-server
(fn [req]
(if (...some code here...)
(handle-ws-connection req)
(handler req)))
(-> opts (dissoc :handler) (assoc :join? false))))
The code above results in the error: Attempting to call unbound fn: #'calcnotes.server.main/handle-ws-connection. Why would the handle-ws-connection be unbound when it is defined above, in the same file?I was pleased when I learned that:
(->> maps (remove #(= (:SKIP %) true)))
collapses to:
(->> maps (remove :SKIP))
so much to learn!Just realized they are not the same. But works for my use case, so still pleased 🙂
It was at exactly the moment when I made such a discovery (while drooling on The Joy Of Clojure in the bay window of a shawarma shop) that I fell off the stool laughing and was hooked.
How to pass variadic args from macro as one argument? So if I have macro
(defn do-smth [sequence])
(defmacro first [& args]
`(do-smth ~@args))
If I do it like that it will pass args to do-smth as multiple arguments.
Is there a way to pass those args as a sequence to defn?two potential short answers - re-list them or quote the list:
(defn do-smth [sequence] sequence)
(defmacro first1 [& args]
`(do-smth '~args))
(defmacro first2 [& args]
`(do-smth (list ~@args)))
(first1 1 2 3)
;=> (1 2 3)
(first2 1 2 3)
;=> (1 2 3)
while the splice could be removed, that would pass an unquoted list, which means it'll be treated as a function call that gets evaluated as a parameter to the fn. Quoting means the list won't be evaluated as a function parameter (which might or might not be what you want), and unsplicing the args into a list call will build the list (which will evaluate function calls within the variadic args:
(first1 5 6 (+ 1 2))
;=> (5 6 (+ 1 2))
(first2 5 6 (+ 1 2))
;=> (5 6 3)
Is there a better way to write this core.async code? If either go blocks fail, the result is nil
, but if the clojure.core.async/map
fails, it blocks forever. I could wrap it a try-catch, but I was curious if there's a more idiomatic way to approach this. For context, I want to kick off two HTTP requests in parallel and then process the results
(a/<!!
(a/map (fn [x y]
(throw (Exception. "Fail"))
(+ x y))
[(a/go 1)
(a/go 2)]))
=> ;; blocks forever
I guess I could just shove the values into a vec, and then use them after
(let [ch (a/map vector [(a/go 1) (a/go 2)])
[x y] (a/<!! ch)]
(throw (Exception. "Fail"))
(+ x y))
Hey team, are there naming conventions for constants in clojure? i.e:
(def default-paths {:a "./foo/bar" :b "./bar/baz"})
It can be hard to tell what is a constant when used in other functions.
I was thinking uppercasing: DEFAULT-PATHS
, or DEFAULT_PATHS
there isn't since almost everything is constant (immutable), you would probably end up with everything in upper case. I have seen it the other way around, some naming conventions for refs, like *my-ref
feel free to make your own conventions though of course. that’s how things become conventions in the wild. people try something and others like it
i tend to see ALL-CAPS as a way to denote global vars that should be considered "constants"
Hey ya’ll does anyone have experience with Opentelemtry Java / Honeycomb in clojure? I’m playing with instrumenting it now. Things work but I am not sure I fully understand how spans link together. Do you know of any articles / example code that shows use in clojure?
I’ve been working on exactly that recently. I have something like this:
(def ^:dynamic *span* nil)
(defn new-span
[span-name]
(when @tracer
(-> @tracer
(.spanBuilder (name span-name))
(cond->
*span* (.setParent (-> (Context/current)
(.with *span*)))
(not *span*) .setNoParent)
.startSpan)))
(defn end-span
[]
(when *span*
(.end *span*)))
(defmacro span
[span-name & body]
`(binding [*span* (new-span ~span-name)]
(try
(do ~@body)
(catch Throwable t#
(.recordException *span* t#)
(throw t#))
(finally
(end-span)))))
I've written quite a dense function with nested let
s and when invoking it the first time I'm getting a ClassCastExpection in the REPL. The exception doesn't tell me much about where the cast is occurring or what symbols are involved. What's the recommended workflow of debugging this? I'm using Cursive.
*e
doesn't have much either
my function looks as dense as many of the library functions I've been reading so I imagined there was some kind of workflow/method for this
if your function is defined in code and require
d you’ll have better line information. write your code in a source buffer, (require <the-namespace> :reload)
to reload the code, and then call it and you should have stack traces with line numbers on them so you know where the error is occurring
but in general, his advice is solid. It’s fun to codegolf and feel clever. But it gets quite tedious to try to figure out where it goes wrong. Writing less clever code can greatly ease in debugging
@U11BV7MTK that worked! Thanks!
I say "dense" with a relative context - dense for me (a beginner). It's function with a let
, a filter
and then a let
inside that filter
which ought to be simple enough. I've seen denser functions in clojuredocs
i have a hotkey to (require <current-namespace> :reload)
and use that almost exclusively. if you eval things individually there are no line numbers so you’re left guessing
Hmmm interesting. Do you know why that's so? I would have thought evaluating functions as I go wouldn't be any different
as an alternative for consideration, Stuart Halloway has talked about an example that might be useful: <https://vimeo.com/223309989#t=1790s>
the repl can’t really track line numbers. if you enter (+ 1 1)
that’s just kinda line 1 right? So evaling stuff can’t really have line numbers. When you require
a namespace, it goes to the file that specifies it and it keeps track of line numbers as it goes through each form in the file
i sent the divide-and-throw
function to the repl. and the line number is REPL:189
which isn’t super helpful
core=> (defn divide-and-throw [x]
(/ x 0))
#'metabase.automagic-dashboards.core/divide-and-throw
core=> (divide-and-throw 3)
Execution error (ArithmeticException) at metabase.automagic-dashboards.core/divide-and-throw (REPL:189).
Divide by zero
if instead i require the namespace i defined it in and then eval a form to call it, my error message can tell me where in the file it occurred:
core=> (divide-and-throw 3)
Execution error (ArithmeticException) at metabase.automagic-dashboards.core/divide-and-throw (core.clj:1724).
Divide by zero
on line 1724
That makes a lot of sense, thanks again! Would have been completely in the dark since I simply didn't have the line number
Following up on this advice, I don't ever type into a REPL. I put scratch code in a file - usually in a (comment ...)
form and use my editor integration to eval it. If you can get used to a workflow like that, you'll find working with Clojure becomes a lot easier.
That's typically what I do, and it's a fantastic experience. I was so used to just evaluating things like that, I never considered reloading namespaces instead of just evaluating functions. I've definitely hit the line numbers problem, and never realized there's such a simple solution. Live coding just got a level up 🙂
yeah. people might not realize that evaluating the form without typing it into the repl actually sends it to the repl
I feel like I knew that's how it worked, but somehow it never really clicked that line numbers are a consequences of loading a namespace and so you wouldn't get them by piecewise building up a namespace by sending forms to the repl
Thanks for spelling that out 👍:skin-tone-2:
@U05N8AJMWQG shameless plug here, but have you seen http://www.flow-storm.org/ ? If I type some contrived one liner like this :
user=> (let [coll [0 "1"] v [:first :second] a (let [b (->> coll (map (fn [n] (v n))))] b)] a)
...
Error printing return value (IllegalArgumentException) at clojure.lang.APersistentVector/null (APersistentVector.java:297).
Key must be integer
I get that exception which doesn't contain any lines. But if in a FlowStorm repl I just evaluate :ex
right after so it moves the debugger into the exception where I see like in the image below, which I find much easier. And you also get to step around.I have not seen FlowStorm, it looks insanely powerful. I'll check it out!
OP mentioned filter & unilluminating *e. That combination can result from lazy sequences. A debugging technique is to wrap a suspect (filter...), (map...), etc., in (doall...) to force the whole sequence to be realized then-and-there.
Or use filterv
and mapv
(eager, producing vectors).