This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-05-11
Channels
- # aleph (3)
- # announcements (3)
- # aws (7)
- # babashka (121)
- # beginners (82)
- # calva (40)
- # chlorine-clover (37)
- # clj-kondo (68)
- # cljsrn (4)
- # clojure (43)
- # clojure-australia (1)
- # clojure-dev (6)
- # clojure-europe (15)
- # clojure-italy (2)
- # clojure-nl (1)
- # clojure-provo (3)
- # clojure-spec (23)
- # clojure-taiwan (1)
- # clojure-uk (21)
- # clojurescript (214)
- # code-reviews (1)
- # conjure (4)
- # core-async (10)
- # cursive (52)
- # datahike (5)
- # datascript (5)
- # datomic (62)
- # duct (1)
- # emacs (4)
- # fulcro (8)
- # graalvm (1)
- # helix (1)
- # honeysql (5)
- # integrant (1)
- # jackdaw (32)
- # jobs (3)
- # jobs-discuss (16)
- # juxt (1)
- # kaocha (3)
- # lsp (6)
- # malli (2)
- # meander (6)
- # nrepl (1)
- # off-topic (46)
- # other-languages (4)
- # pathom (7)
- # polylith (13)
- # re-frame (3)
- # releases (2)
- # shadow-cljs (56)
- # spacemacs (15)
- # tools-deps (3)
- # unrepl (1)
- # utah-clojurians (1)
Hello. Was looking for information on when to use a case
form and when to use multimethods (I want to dispatch on value), and also some performance comparisons. And I came across this https://insideclojure.org/2015/04/27/poly-perf/. When Alex says case
is "closed", does that mean anything more than "one has to add another case condition"? In contrast, multimethods are "open" because, you have define a multimethod external to the defmulti? Not quite able to understand why case is more closed than multimethods. If I need to make some changes to the value I'm dispatching on, I have to change the mulimethod definition as well isn't it?
One major difference between case
and defmulti
is that defmulti
is more flexible. There's a couple of ways the difference in flexibility manifests. For case
, there's really only one way to add an additional clause which is to add another clause within the case statement. For defmulti
, there are multiple options for extending a multi method. For programs that are fairly static, the code for using either defmulti
or case
might look largely the same. but for a dynamic program, defmulti
's flexibilty can really shine.
Two types of extra flexibility come to mind.
1. Allowing library users to provide extensions. See https://clojuredocs.org/clojure.core/print-method for an example
2. Extending multi methods at run time. Typically, programs don't take advantage of this in production, but it's pretty useful in development if you're doing repl driven development. The idea is that you create a multi method that has 0 clauses and add/update clauses using your attached repl until everything works.
Thanks, the library bit makes sense. Need to try out the REPL friendliness of multimethods. 👍:skin-tone-4:
re the original question, you had it. multimethod methods can be extended after the fact without changing the defmulti. case will require all cases to be defined at the same place.
if you are using a third party library where things are defined as case over defmulti in your code you are able to extend the defmulti, but not the case..
is there any name-spaced syntax for set similar like map, #{:a.b/foo :a.b/bar :a.b/baz} can i take this a.b out for once?
no, but even for maps you can’t take multiple values only by namespace
#:a.b {:foo 123 :bar 123}
in map i can do this,
and the key would all become :a.b/foo :a.b/bar, i guess there's no such thing for set then 😄
no, maps only. the syntax would be pretty ugly for sets #:a.b#{:foo 123}
- that seemed bad :)
still sitting on the fence about vectors
Does anyone have any idea what this error might be due to? I think it happens in a Luminus project where I am trying to set up Sente. The error happens when Sente tries to connect to the server. I would love some hints on how to debug it or tips if anyone knows what might be wrong.
java.lang.IllegalArgumentException: No implementation of method: :on-close of protocol: #'org.httpkit.server/Channel found for class: nil
at clojure.core$_cache_protocol_fn.invokeStatic(core_deftype.clj:583)
at clojure.core$_cache_protocol_fn.invoke(core_deftype.clj:575)
at org.httpkit.server$eval19781$fn__19851$G__19772__19858.invoke(server.clj:96)
at taoensso.sente.server_adapters.http_kit.HttpKitServerChanAdapter.ring_req__GT_server_ch_resp(http_kit.clj:25)
at taoensso.sente$make_channel_socket_server_BANG_$fn__21615.invoke(sente.cljc:606)
at muuntaja.middleware$wrap_params$fn__8119.invoke(middleware.clj:52)
at muuntaja.middleware$wrap_format$fn__8123.invoke(middleware.clj:73)
at everclear.middleware$wrap_formats$fn__9289.invoke(middleware.clj:41)
at ring.middleware.anti_forgery$wrap_anti_forgery$fn__6955.invoke(anti_forgery.clj:94)
at ring.middleware.params$wrap_params$fn__9021.invoke(params.clj:67)
at ring.middleware.keyword_params$wrap_keyword_params$fn__8807.invoke(keyword_params.clj:53)
at reitit.ring$ring_handler$fn__24478.invoke(ring.cljc:326)
at clojure.lang.AFn.applyToHelper(AFn.java:154)
at clojure.lang.AFn.applyTo(AFn.java:144)
at clojure.lang.AFunction$1.doInvoke(AFunction.java:31)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.lang.Var.invoke(Var.java:384)
at ring.middleware.reload$wrap_reload$fn__4448.invoke(reload.clj:39)
at selmer.middleware$wrap_error_page$fn__4463.invoke(middleware.clj:18)
at prone.middleware$wrap_exceptions$fn__4704.invoke(middleware.clj:159)
at ring.middleware.flash$wrap_flash$fn__8160.invoke(flash.clj:39)
at ring.middleware.session$wrap_session$fn__8605.invoke(session.clj:108)
at ring.adapter.undertow.middleware.session$wrap_undertow_session$fn__8711.invoke(session.clj:88)
at ring.middleware.keyword_params$wrap_keyword_params$fn__8807.invoke(keyword_params.clj:53)
at ring.middleware.nested_params$wrap_nested_params$fn__8865.invoke(nested_params.clj:89)
at ring.middleware.multipart_params$wrap_multipart_params$fn__8997.invoke(multipart_params.clj:171)
at ring.middleware.params$wrap_params$fn__9021.invoke(params.clj:67)
at ring.middleware.cookies$wrap_cookies$fn__8484.invoke(cookies.clj:214)
at ring.middleware.absolute_redirects$wrap_absolute_redirects$fn__9209.invoke(absolute_redirects.clj:47)
at ring.middleware.resource$wrap_resource_prefer_resources$fn__9057.invoke(resource.clj:25)
at ring.middleware.content_type$wrap_content_type$fn__9157.invoke(content_type.clj:34)
at ring.middleware.default_charset$wrap_default_charset$fn__9181.invoke(default_charset.clj:31)
at ring.middleware.not_modified$wrap_not_modified$fn__9123.invoke(not_modified.clj:61)
at ring.middleware.x_headers$wrap_x_header$fn__8747.invoke(x_headers.clj:22)
at ring.middleware.x_headers$wrap_x_header$fn__8747.invoke(x_headers.clj:22)
at ring.middleware.x_headers$wrap_x_header$fn__8747.invoke(x_headers.clj:22)
at everclear.middleware$wrap_internal_error$fn__9283.invoke(middleware.clj:20)
at ring.adapter.undertow$undertow_handler$fn$reify__42283.handleRequest(undertow.clj:33)
at io.undertow.server.Connectors.executeRootHandler(Connectors.java:370)
at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:830)
at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:2019)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1558)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1449)
at java.base/java.lang.Thread.run(Thread.java:831)
I get this error in the developer console by the way:
sente.cljc:1045 WebSocket connection to '' failed:
eval @ sente.cljc:1045
core.cljs:159 ERROR [taoensso.sente:1058] - WebSocket error: [object Event]
eval @ core.cljs:159
These are the relevant lines mentioned in the stack trace (from middleware.clj
):
17 (defn wrap-internal-error [handler]
18 (fn [req]
19 (try
20 (handler req)
21 (catch Throwable t
22 (log/error t (.getMessage t))
23 (error-page {:status 500
24 :title "Something very bad has happened!"
25 :message "We've dispatched a team of highly trained gnomes to take care of the problem."})))))
26
27 (defn wrap-csrf [handler]
28 (wrap-anti-forgery
29 handler
30 {:error-response
31 (error-page
32 {:status 403
33 :title "Invalid anti-forgery token"})}))
34
35
36 (defn wrap-formats [handler]
37 (let [wrapped (-> handler wrap-params (wrap-format formats/instance))]
38 (fn [request]
39 ;; disable wrap-formats for websockets
40 ;; since they're not compatible with this middleware
41 ((if (:websocket? request) handler wrapped) request))))
it's also available in this library: https://github.com/babashka/fs/blob/05d392933a4e6fe0e0c3fa002c1bdeeccc995801/src/babashka/fs.cljc#L527
my use case would be reading a binary input stream (ring request body), checking how long the contents are and writing it into a file
you could just use the http://java.io inputstreams for this kind of thing
Logging in java is such a frustration. I imported clj-http that messed with my current logging and logs stopped showing up on my cider. Is there a way to turn off the logging from clj-http?
@munichlinux What are you currently using for logging?
@seancorfield here is my setup:
[org.apache.logging.log4j/log4j-api "2.14.1"]
[org.apache.logging.log4j/log4j-core "2.14.1"]
[org.apache.logging.log4j/log4j-jcl "2.14.1"]
[org.apache.logging.log4j/log4j-jul "2.14.1"]
[org.apache.logging.log4j/log4j-1.2-api "2.14.1"]
here is my log4j2.xml:
<?xml version= "1.0" encoding= "UTF-8" ?>
<Configuration monitorInterval= "10" >
<Appenders>
<!-- console output -->
<Console name= "Console" target= "SYSTEM_OUT" >
<PatternLayout pattern= "[%level] - %d %logger %m%n%throwable" />
</Console>
</Appenders>
<Loggers>
<Logger name= "io.grpc.netty.shaded.io" level= "ERROR" >
<AppenderRef ref= "Console" />
</Logger>
<Logger name="org.apache.http" level="OFF" >
</Logger>
<Root level= "all" includeLocation= "false" >
<AppenderRef ref= "Console" level= "DEBUG" />
<AppenderRef ref= "Console" level= "ERROR" />
<AppenderRef ref= "Console" />
</Root>
</Loggers>
</Configuration>
And you’re using tools.logging
to do your actual logging, yes?
Read over this section: https://github.com/clojure/tools.logging/#selecting-a-logging-implementation
What I believe is happening is that previously, tools.logging
was picking up log4j2 by default but when you introduced clj-http
, it depends on commons logging which tools.logging
“prefers”, so you need to explicitly tell it to use log4j2 anyway (via the JVM option described in that link).
@seancorfield yes using tools.logging.
@seancorfield I added that to :repl
section
:repl {:jvm-opts ["-Dclojure.tools.logging.factory=clojure.tools.logging.impl/log4j2-factory"]}
Are you sure that however you are starting up your Clojure process is using that? (profile/alias)
Then ask in #cider — I haven’t used that for years so I can’t help you, sorry.
Hi, im having a bit of an issue calling a package private function from a base class. After doing a bunch of googling it seems others have had some problems too and was wondering if anyone had a solution?
@kierand Can you provide a bit more context? That doesn’t sound like a Clojure problem…?
so i have the following code
(def pca
(-> (PublicClientApplication/builder client-id)
(.authority auth)
(.build)))
but .authority is inherited from an abstract class
so when i try to call it i get Reflection warning, clojure_ad_test/core.clj:22:7 - call to method authority on com.microsoft.aad.msal4j.PublicClientApplication$Builder can't be resolved (argument types: unknown).
That says it can’t figure out the type of auth
so it doesn’t know what method to call.
You’ll have to type hint auth
, either where you declare it, or inline.
Try (.authority ^String auth)
Based on these docs: https://javadoc.io/doc/com.microsoft.azure/msal4j/1.0.0/com/microsoft/aad/msal4j/PublicClientApplication.Builder.html
i tried that but i get the same errror
except type unknown is now java.lang.String
fyi those docs are wrong the actual signature of builder is public static class Builder extends com.microsoft.aad.msal4j.AbstractClientApplicationBase.Builder<PublicClientApplication.Builder>
Reflection warning, clojure_ad_test/core.clj:23:7 - call to method authority on com.microsoft.aad.msal4j.PublicClientApplication$Builder can't be resolved (argument types: java.lang.String).
Reflection warning, clojure_ad_test/core.clj:24:7 - reference to field build can't be resolved.
Execution error (IllegalArgumentException) at clojure.main/main (main.java:40).
No matching method authority found taking 1 args for class com.microsoft.aad.msal4j.PublicClientApplication$Builder
thats the entire stack trace
On Clojure 1.8, we get a different error:
(! 1452)-> clj -Sdeps '{:deps {com.microsoft.azure/msal4j {:mvn/version "1.0.0"}}}' -A:1.8
Clojure 1.8.0
user=> (import 'com.microsoft.aad.msal4j.PublicClientApplication)
com.microsoft.aad.msal4j.PublicClientApplication
user=> (let [b (PublicClientApplication/builder "foo")] (.authority b "bar"))
IllegalArgumentException Can't call public method of non-public class: public com.microsoft.aad.msal4j.ClientApplicationBase$Builder com.microsoft.aad.msal4j.ClientApplicationBase$Builder.authority(java.lang.String) throws java.net.MalformedURLException clojure.lang.Reflector.invokeMatchingMethod (Reflector.java:88)
user=> ^D
(! 1453)-> clj -Sdeps '{:deps {com.microsoft.azure/msal4j {:mvn/version "1.0.0"}}}' -A:1.10
Clojure 1.10.3
user=> (import 'com.microsoft.aad.msal4j.PublicClientApplication)
com.microsoft.aad.msal4j.PublicClientApplication
user=> (let [b (PublicClientApplication/builder "foo")] (.authority b "bar"))
Execution error (IllegalArgumentException) at user/eval138 (REPL:1).
No matching method authority found taking 1 args for class com.microsoft.aad.msal4j.PublicClientApplication$Builder
user=>
I wonder if @ghadi can shed some light on this?(ISTR this is an area where Clojure has made some changes over the years but I’m cloudy on what they were)
I thought it sounded a bit familiar. I’ve upvoted that ask issue.
This is an old problem (https://clojure.atlassian.net/browse/CLJ-1243 ) that really links back to an even older still open issue in Java https://bugs.java.com/bugdatabase/view_bug.do?bug_id=4283544
yeah i went through all of those issues and they all seem to end at a dead end
if you are just looking for a work around to make it work something like
(import 'com.microsoft.aad.msal4j.PublicClientApplication)
(def authority
(.findVirtual
(java.lang.invoke.MethodHandles/lookup)
com.microsoft.aad.msal4j.PublicClientApplication$Builder
"authority"
(java.lang.invoke.MethodType/methodType
com.microsoft.aad.msal4j.ClientApplicationBase$Builder
[String])))
(let [b (PublicClientApplication/builder "foo")]
(.invokeWithArguments authority [b "foo"]))
should workyep that works i had to make small change from com.microsoft.aad.msal4j.ClientApplicationBase$Builder
to com.microsoft.aad.msal4j.AbstractClientApplicationBase$Builder
but i can call the method.
Thanks so much!!
wow. this one was kinda sounding impossible to get the Clojure compiler to output the correct bytecode
so just out of curiousity - is this something that clojure can fix or something that has to be fixed at a java level?
there are kind of two ways method invoking like (.authority b "foo")
can get compiled
one way is without reflection, which the compiler does if it knows all the types, but there appears to be a clojure bug somewhere so it is failing to do that
if a method call cannot be compiled without reflection, the compiler generates code that will do a reflective call at runtime, which would hit the underlying java issue
Ah so it's trying reflection because it should know the types but then the bug stops it from getting the abstract class it inherits from?
Would it be possible to point a function at a directory on my computer, have it find all of the image files, and then create a map according to this schema?
What about imagez? https://github.com/mikera/imagez It might be a bit heavy for this though, but it lets you get image width and height. Here's a quick example:
(defn get-image-properties [path file]
(let [img (mimg/load-image (str path "//" file))]
{:measuremnt {:width (mimg/width img)
:height (mimg/height img)}}))
(let [path "//home/stuart//Pictures"
files (->> (.list (io/file path))
(filter #(str/ends-with? % ".png")))]
{:images (zipmap (map keyword files)
(map (partial get-image-properties path) files))})
This outputs:
{:images
{:Selection_023.png {:measuremnt {:width 842, :height 412}},
:Selection_025.png {:measuremnt {:width 600, :height 426}},
:Selection_020.png {:measuremnt {:width 850, :height 340}},
:Selection_024.png {:measuremnt {:width 602, :height 426}},
:Selection_021.png {:measuremnt {:width 1292, :height 965}},
:Screenshot from 2021-04-12 00-22-05.png {:measuremnt {:width 857, :height 335}},
:Selection_026.png {:measuremnt {:width 1000, :height 426}},
:puzzle-storm-33.png {:measuremnt {:width 850, :height 340}}}}
Looks like you have a couple of dependencies set up here. What’s in your namespace?
(ns reference.core
(:gen-class)
(:require [clojure.string :as str]
[ :as io]
[mikera.image.core :as mimg]))
Thanks! I’m a little confused what’s going on with (str path "//" file)
and the (let [path "//home/stuart//Pictures"
would you mind explaining?
Yeah I guess also just what are you putting in the path and file arguments?