This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-06-05
Channels
- # announcements (11)
- # architecture (22)
- # babashka (33)
- # beginners (15)
- # biff (8)
- # calva (7)
- # clj-otel (1)
- # cljs-dev (3)
- # cljsrn (5)
- # clojure (76)
- # clojure-art (1)
- # clojure-europe (36)
- # clojure-hamburg (3)
- # clojure-nl (1)
- # clojure-norway (7)
- # clojure-poland (12)
- # clojure-spec (2)
- # clojure-uk (7)
- # clojurescript (9)
- # cursive (22)
- # data-science (6)
- # datomic (7)
- # fulcro (9)
- # hoplon (14)
- # instaparse (2)
- # jobs-discuss (14)
- # london-clojurians (1)
- # matrix (32)
- # music (1)
- # nbb (8)
- # off-topic (18)
- # pathom (29)
- # pedestal (6)
- # portal (34)
- # reagent (2)
- # reitit (4)
- # releases (1)
- # sci (10)
- # shadow-cljs (7)
- # tools-deps (4)
- # vim (6)
I’ve run into an unexpected issue when using deftype
. I’m using a java library with various functional interfaces (:face_with_rolling_eyes:), and I’m trying to make using clojure function with them as seemless as possible, so I’ve done this:
(deftype CustomFn [f]
Handler
(handle [_ event]
(f event))
Function
(apply [_ args]
(f args)))
Unfortunately, it seems that when I call
(.doThingWithHandler x (->CustomFn my-fn))
, I still need to type hint the result of ->CustomFn
to avoid reflection (using ^Handler
, ^CustomFn
doesn’t help). Is there something I can do to ensure that CustomFn
is treated as both Function
and Handler
without polluting the code based with type hints everywhere I use it?I'm not sure you need your own custom type. Usually you pass an object made with reify
.
(.doThingWithHandler x (reify SomeInterface
(do-this [_ arg1 arg2]
(call-my-func arg1 arg2))))
Yeah, I could
(defn ->custom-fn [f]
(reify
Handler
(handle [_ event]
(f event))
Function
(apply [_ args]
(f args))))
But then there’s no way to type hint this as both Handler
and Function
, which would be convenient. Maybe I’m asking for a lot and I should just be reifying adding type hints on the invocation itself, I was just hoping to avoid that.Hm, passing a result of reify is usually enough to mute reflection warnings. Are you sure you implement the right interface? Does this code work?
Yeah, it’s because it’s in a function, if I had reify
inline it would work, but at that point I’d rather just type hint.
you can use this then:
(defn ->custom-fn ^SomeInterface [f] ...)
so every call of this function is aware of the result typeThis would work well if I had just one interface, but I need to type hint the result as both Function
and Handler
, and I was hoping to avoid treating these differently. Oh well, I guess Java interop code is never all that clean, I guess I’ll either compromise on in-line type hinting or on treating the two interfaces differently
That’s an option, I was just hoping to avoid that as the two functional interfaces both behave the same (1 arg, non-void return value). I thought having a value of type CustomFn
(that implements these interfaces) would allow clojure to read it as both of these types and for me to use them indiscriminately, but given that’s not the case I will either have two different type-hinted reifying functions, or type hint in line.
@U02634NQ5MK Make a protocol/interface that extends all the interfaces
(gen-interface
:name mypkg.CustomFn
:extends [io.vertx.core.Handler java.util.function.Function])
(defn- ^mypkg.CustomFn ->vertx-fn [f]
(proxy [mypkg.CustomFn] []
(handle [event]
(f event))
(apply [arg]
(f arg))))
This ended up solving the problem. Using gen-interface
here feels a bit over the top but I guess it gets the job donehi folks 👋 I am trying to remember there was a library which I think was inspired by re-frame but was for the backend to plumb IO, does that sound familiar to anyone? My google-fu is letting me down...
yes this is very similar to what I was thinking of but the project is much younger than I was thinking of, as I definitely came across this at least more than a year ago IIRC
https://github.com/pitch-io/uix can be worth attention
“better” than re-frame because base on new solutions while re-frame was created much earlier when things didn’t exist
thanks for this, not really looking for a front end library, more the paradigm of using effects to model IO
I was surprised by this:
user=> (nth [] 0) ;; makes sense
Execution error (IndexOutOfBoundsException) at user/eval1 (REPL:1).
null
user=> (nth () 0) ;; makes sense
Execution error (IndexOutOfBoundsException) at user/eval3 (REPL:1).
null
user=> (nth nil 0) ;; surprise
nil
Is this expected?It does have counter-intuitive consequences:
;; A
(nth *command-line-args* 0) ;; throws
;; B
(defn main [& args] (nth args 0))
(apply main *command-line-args*) ;; doesn't throw
Normally I'd consider A->B a safe refactoring
(In fact that's what tripped me up just now)
Thanks for finding the Jira @U2FRKM4TW. I agree that changing this behavior is undesirable for backward-compatibility reasons
Ah. I myself have dropped EAFP along with dropping Python in favor of LBYL or functions that just don't throw. :)
In this case, I'd use first
or destructuring. I use nth
pretty much only on vectors and maybe strings.
Right, I'm using (or (first args) (throw (Exception. "...."))) now as a remedy
I didn't know about EAFP vs LBYL - will read up about that
tl;dr: don't rely on something throwing an exception when you can check or, better yet, rely on nil punning.
what is a safe way of checking if something is a map and contains a key? Doing (and (map? m) (contains? m :k))
will throw for example for m
being a sorted-map of symbol keys because the comparator can't compare keywords with symbols
(let [m (sorted-map 'a 10)]
(and (map? m)
(contains? m :k)))
java.lang.ClassCastException: class clojure.lang.Symbol cannot be cast to class clojure.lang.Keyword
I have this code for that
(defn get-safe
([key] #(get-safe % key))
([map key]
(when (map? map)
(try (get map key) ;; can throw for e.g. sorted-map
(catch #?(:clj Exception :cljs js/Error) _e nil)))))
yeah I was about to do the same, but seems hacky
it is also one of those bugs that is hard to figure out in dev when you are writing generic code
I think this should be safe for anything map-like? (including seqs-of-pairs) It's still a bit hacky, but concise with no need to catch exceptions.
(defn has-key? [m k]
(->> m keys (filter #{k}) count pos?))
(let [m (sorted-map 'a 10)]
[(has-key? m :k) (has-key? m 'a)])
; =>
[false true]
but that is going to be pretty slow for big maps
Hello guys! I am trying to write a testing framework which will be used to run integration tests. The issue I am encountering is that I can't control the output of System/CurrentTimeMillis
I tried to redef
it but it didn't work. Can you suggest a solution?
Could you refactor lines that use that function to use a wrapper that you can redefine?
Here's an example of doing just that. The https://github.com/cljdoc/cljdoc/blob/8f9126033b707a88a4d12be0532c3c8811e58e88/src/cljdoc/util/sqlite_cache.clj#L15-L18 and the https://github.com/cljdoc/cljdoc/blob/8f9126033b707a88a4d12be0532c3c8811e58e88/test/cljdoc/util/sqlite_cache_test.clj#L53-L58.
@U2FRKM4TW I will have to rewrite pretty much of the whole project and in the future whenever someone will use the function he will always have to use the same wrapper function name
Another technique is to use JDK8+ https://docs.oracle.com/javase/8/docs/api/java/time/Clock.html. But in any case, you need a mechanism to optionally insert yourself into a function that fetches time.
Briefly, there is no a way to just redefine a System/CurrentTimeMillis
call. Either wrap it into a function, or implement any kind of inversion where you pass an object responsible for getting time. Then pass a fake object in tests.
Thanks for your replies
I must be having a dense day
(async/go
(loop []
(while (not @closed?)
(let [v (async/<! x)]
( v channel)
(recur)))))
it complains about tail position. What would the correct rewrite?while
is sugar for loop
+`recur`, so you end up having two recur
s in the inner loop.
I suspect you meant to make that while
a when
, but while
is probably more semantically correct and you should drop recur
and loop
The original form was go-loop, I unbundled it trying to debug the issue, which is why it looks extra bad
It can be useful to macroexpand inner forms to see what is going on with them when you have problems. If you try to macroexpand something that's not a macro, it just returns unmodified, so it's safe and easy to try anywhere. Typically there's an editor shortcut to do it, but here's the repl way:
(macroexpand
'(while (not @closed?)
(let [v (async/<! x)]
( v channel)
(recur))))
becomes
(loop*
[]
(clojure.core/when (not @closed?)
(let [v (async/<! x)] ( v channel) (recur))
(recur)))

BTW, why do you need the closed atom? You can close the channel and taking from it returns nil (you should check it, btw)
Sure thing! Thanks.
(async/go-loop []
(when-let [v (async/<! x)]
( v channel)
(recur)))
;; and (async/close! x) elsewhere
This is exactly the circumstance that I want while-let
for
And you want to handle an exception in case send
fails because you might want to stop recurring or recover
(defmacro while-some
[test & body]
`(loop []
(when-some ~test
~@body
(recur))))
(a/go
(while-some [v (a/<! x)]
( v channel)))
This makes it pretty nice
Additionally, if you want to cascade shutdown, you can close the websocket channel after you finish the loop
(a/go
(while-some [v (a/<! x)]
( v channel))
( channel)) ;; guessing the API looks like that
It looks different (if you're curious) https://kit-clj.github.io/docs/websockets.html - the closing goes on :on-close-message
I found it an elegant extension to Ring :)
The same handler can respond to vanilla and websocket requests alike (which I had to achieve, for reasons):
(if x
{:status 200 :body "hello vanilla"}
{:undertow/websocket {:on-open f
:on-message g
:on-close-message h}})
Also note, undertow’s send is generally non-blocking. If your intent is for the loop to recur when the send is done, you may need to wrap it.
That would be interesting. Are you talking about https://github.com/luminus-framework/ring-undertow-adapter/blob/3b27314d3eb040c17a0e8dae081adead4feb844f/src/ring/adapter/undertow/websocket.clj#L88-L97 send? If it indeed is async, it would be a great doc addition
Yes! That one. I wrapped it like so: (defn go-send "Non-blocking send. Returns a channel that will close when the message sends. Propagates errors." [msg ws-conn] (let [ch (promise-chan)] (ws/send msg ws-conn (proxy [WebSocketCallback] [] (complete [ws-conn context] (a/close! ch)) (onError [ws-conn context throwable] (a/put! ch throwable) (a/close! ch)))) ch))
Nice. I will create an issue there if you wouldn't want to do it yourself. At the very least it seems wise to document the behavior, else bugs can happen (in my snippet, I could imagine out-of-order delivery)
@U0C5DE6RK: another approach being to use the *blocking
methods, opt-in:
- WebSockets/sendBinary
+ WebSockets/sendBinaryBlocking
would make a nice PR, I could do thatOne thing to be careful about with the blocking methods, is that it could block core async’s underlying thread pool. (This gentleman has a good explanation https://martintrojer.github.io/clojure/2013/07/07/coreasync-and-blocking-io). I am not sure how big of a problem this would be though. For the library a blocking option could be a good PR! :right-facing_fist: :left-facing_fist:
Yeah I was aware, I was using (<! (thread (blocking-thing)))
(at least for the time being... I guess it performs OK)
loom will help with this a lot because you can just make everything its own thread and don't have to worry about starvation (with the caveats about running native code and currently on monitors as well)