This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-08-09
Channels
- # announcements (3)
- # babashka (120)
- # beginners (87)
- # calva (7)
- # clj-kondo (35)
- # cljsrn (25)
- # clojure (94)
- # clojure-austin (4)
- # clojure-europe (53)
- # clojure-nl (2)
- # clojure-norway (6)
- # clojurescript (16)
- # conjure (8)
- # cursive (6)
- # data-oriented-programming (2)
- # data-science (19)
- # datahike (1)
- # datalevin (29)
- # datomic (13)
- # fulcro (50)
- # gratitude (1)
- # honeysql (9)
- # jackdaw (2)
- # kaocha (7)
- # leiningen (3)
- # malli (4)
- # off-topic (4)
- # polylith (3)
- # re-frame (5)
- # reagent (1)
- # releases (1)
- # reveal (4)
- # shadow-cljs (17)
- # tools-deps (10)
- # vim (17)
- # vscode (4)
- # xtdb (3)
I have a java function from a 3rd party lib, e.g., (my-func) which returns an object of type SomeType. That type has a close
method.
Now I want to wrap that object, but override its close
method. What approach can I take? proxy
?
Could you use deftype? Implement Closeable. Just use a plain function (close-xxx)? If this is something used as part of configuration, could you use Integrant (or similar) and do whatever you need in the halt method?
You should probably wrap the object and delegate all method calls except close
to the underlying object.
Is SomeType an interface or a concrete class?
Then can you use proxy
to instantiate an object of SomeType and make it delegate all the stuff except close
to the wrapped object?
With proxy
you make an instance of SomeType and implement it in the way that it passes all the calls to the wrapped object except the close
method call.
Btw. I realized you don't need to implement any other methods except close
- see https://github.com/jumarko/clojure-experiments/pull/29/files#diff-813208f4514480f7a8f4fc6259a5ee673db0c2c7700c06ca3369ab7d5af09c1cR88
So a minimal example would be something like:
(let [filename "empty.zip"
original-zip (ZipFile. filename)
proxy-zip (proxy [ZipFile] [filename]
;; overriding close method
(close [] (println "Ignored!")))]
[[(.getName proxy-zip) (.getName original-zip)]
;; check the REPL - you will see "Ignored!" printed one time
[(.close proxy-zip) (.close original-zip)]])
@UGC0NEP4Y does this approach work for you or you hit some issues?
@U06BE1L6T Thanks for the code. Take the Zip class for example, if https://github.com/jumarko/clojure-experiments/blame/master/src/clojure_experiments/java.clj#L101 the filename is not given, so the only thing accessible original-zip, what can we do?
How can the filename (or similar information required by the constructor) be not given? If you didn't know that, you couldn't construct the original object.
> I have a java function from a 3rd party lib, e.g., (my-func) which returns an object of type SomeType. It’s hidden in the 3rd party lib inside the function my-func.
If you are not able to construct the object then I'm afraid this is not possible. In most cases, there will be a constructor which you can use and some kind of "getter" to get the information you need from the object. Is this is an open source library? It would be great if you could provide a code sample.
The problem was addressed to use another lib and the problem has gone. I was trying to understand the possibility.
Just wondering – why does the clojure docs for <
and similar say they "return non-nil if nums..." – in what case does it not return something else than true
if the condition holds?
Even clojure.lang.Numbers
have boolean
marked as the return value for lt
and others
This is the general pattern for Clojure functions, when you expect a boolean it will specify "non-nil" instead of "true", because this allows the contract to not be broken if the actual return value is changed down the line.
In the specific case of the math comparison operators, there's not likely to be any change there, but many functions that might conceptually return a boolean return an object because of the pattern of returning "the most useful thing". e.g. or
and and
in other languages might return only a boolean, but in Clojure they return more valuable values.
Thanks!
No problem!
Yes, for or
, and
et al I understand this completely, but for math ops it was not clear. 🙂
I've just read on reddit that cognitect is against pattern matching, which is controversial. I can't find any discussion of this. Is there any? Or maybe a hint of why? I got used to it in erlang. Why would pattern matching work less great in clojure, at least readability-wise?
I think it's less about readability and more about coupling. I think that any time you have a case/cond/etc you create a branching code structure that is closed for extension. Pattern matching (in a lot of languages) is often a dispatch-on-type kind of operation, and often dispatching on types that you don't own. This sounds a lot like polymorphism and could perhaps be better served using protocols or multimethods. I've not done a lot of erlang, so I don't feel in a position to comment on that vs something like core.match ... but I think the point is more about questioning if you're using the right language construct for the job rather than a hard and fast rule 😉
https://gist.github.com/reborg/dc8b0c96c397a56668905e2767fd697f#why-no-pattern-matching
@U06BE1L6T, thanks, this should be pinned basically everywhere haha
Still, if you want to at least see what pattern matching could bring you can use either https://git.sr.ht/~technomancy/fnl-match or https://github.com/clojure/core.match 🙂
and https://github.com/xapix-io/matchete 🙂 there are many more or less active libraries providing pattern-matching abilities
In the https://clojure.org/guides/deps_and_cli there's an example of using tags:
> {:deps {io.github.yourname/time-lib {:git/tag "v0.0.1" :git/sha "4c4a34d"}}}
Can't the tag and the sha get out of sync? What will happen in that case?
As far as I can gather, tags can be moved: https://stackoverflow.com/a/20076601/202538
Yes, tags can be moved, but this is actually the reason the sha is included in the first place. If we only had the tag then we would have no way of knowing if the tag was moved. With the sha included, if the tag is moved then the build will fail, and you as the developer have the opportunity to then go browse your dependency to determine the most appropriate version to use.
Yes. Adding the tag however allows you to use a short sha instead of the full one.
https://clojure.org/reference/deps_and_cli#_git here is a full reference for those options
The fact that it goes and checks the tag against the sha on every single build is actually annoying because it means you can never build offline: https://clojure.atlassian.net/browse/TDEPS-223
if that's a concern to you at all, I suggest using full the sha and no tag instead
tag = semantic meaning for humans sha = specific commit for comparison
tag + short sha gives you semantics plus verification against a moved tag
if tag and short sha don't point to the same peeled commit, you'll get an error
I believe the same even happens with tag + full sha
yes, correct
Why doesn't this work?
(import jdk.jshell.JShell)
(.create JShell)
Execution error (IllegalArgumentException) at user/eval49408 (form-init14822045749768224231.clj:1).
No matching field found: create for class java.lang.Class
sanity check:
(take 10
(eduction
(map println)
(range 100000)))
;; returns (nil nil nil nil nil nil nil nil nil nil)
;; but nothing is printed
just inf-clojure with a custom print fn in the repl that basically tries to prevent massive output, turns out to be related to that but not sure how yet
in inf-clojure I’m seeing:
database-test=> (take 10
(eduction
(map println)
(range 100)))
0
1
2
3
4
...
31
32
(nil nil ... nil)
(clojure.main/repl
:print (fn [x]
(binding [*print-length* 100
*print-level* 20]
(if (> (count (pr-str x)) 3e6)
(log/warn "<string too big>")
(pprint/pprint x)))))
yeah i get the same with your repl. You should add :read clojure.core.server/repl-read
so you can quit it with :repl/quit
it works fine for me to just create a new one, but thanks for the tip that's probably better
I’m using
(clojure.main/repl
:print (fn [x]
(tap> [:print-called x])
(try
(if (> (count (pr-str x)) 10)
(log/warn "<string too big>")
(pprint/pprint x))
(catch Exception e (tap> "caught an exception") (tap> e))))
:read server/repl-read
:prompt (fn [] (printf "sub %s=> " (str *ns*))))
with the :read
there i’m able to send :repl/quit
and change things in the print function to help diagnose.ah good catch @U0NCTKEV8. that has with-out-str
in it.
user=> (pr-str
(take 10
(eduction
(map println)
(range 100000))))
"(0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n25\n26\n27\n28\n29\n30\n31\n32\nnil nil nil nil nil nil nil nil nil nil)"
user=>
interjection but how do I customize my REPL like that? Is there a walkthrough on it somewhere?
then because of the call to take, the eduction is wrapped in a lazy seq, which caches the results of the compuation, so the second time through with pprint you just get a seq of nils
if you are using nrepl i think you are out of luck. If you are using a regular repl then the forms i’ve posted here will work fine for you. the server
alias is clojure.core.server
Here’s my standard repl:
(clojure.main/repl
:prompt (fn [] (printf "%s=> " (peek (str/split (str *ns*) #"\."))))
:eval (fn [f] (binding [clojure.test/*test-out* *out*] (eval f)))
:read server/repl-read
:print fipp/pprint)
regular REPL as in started with clj
or clojure
and not through Cider or the like
> regular REPL as in started with clj or clojure and not through Cider or the like
yeah then you can just call clojure.main/repl
with the args described here:
https://clojuredocs.org/clojure.main/repl
@U03QBKTVA0N yeah. CIDER
connects through nrepl which can’t work with subrepls like this. If you try it you’ll see if asks for input from the minibuffer (i believe, been a while)
cool, well I'll explore my options. thanks! (excuse the off-topic noise) @U11BV7MTK @U064UGEUQ
I'm running clj -Sdeps '{:deps {somedep/somedep {:mvn/version "2.3.128"}}}'
and it is complaining with Error building classpath. Could not find artifact com.github.Dansoftowner:jSystemThemeDetector:jar:3.8 in central (
.
Looking at the dependency jar pom it has repositories :
<repositories>
<repository>
<id>clojars</id>
<url> </url>
</repository>
<repository>
<id>jitpack</id>
<url></url>
</repository>
</repositories>
and that failing dependency is from the jitpack one. Any ideas why cli deps maybe only checking clojars and central and skipping the others?searching for artifacts doesn't use repository settings from dependencies, so you'll need to configure any additional repositorie
yeah I found this https://clojure.atlassian.net/browse/TDEPS-46
> you'll need to configure any additional repositorie you mean that all users of the library will have to add it to their setup?
damn, I guess I'll just deploy that jar on clojars under my group :man-shrugging:
thanks!
Can someone explain how a PersistentArrayMap would sometimes not implement iFn? I got this stack trace very rarely in a production environment running JDK11 and Clojure 1.8:
java.lang.ClassCastException: class clojure.lang.PersistentArrayMap cannot be cast to class clojure.lang.IFn (clojure.lang.PersistentArrayMap is in unnamed module of loader Something @344d449f; clojure.lang.IFn is in unnamed module of loader Something @23b521ad)
at clojure.core$comp$fn__4730.invoke(core.clj:2461)
at clojure.core$filter$fn__4815.invoke(core.clj:2713)
at clojure.lang.LazySeq.sval(LazySeq.java:40)
at clojure.lang.LazySeq.seq(LazySeq.java:49)
at clojure.lang.RT.seq(RT.java:521)
at clojure.core$seq__4360.invokeStatic(core.clj:137)
at clojure.core$seq__4360.invoke(core.clj:137)
at clojure.core$filter$fn__4815.invoke(core.clj:2702)
at clojure.lang.LazySeq.sval(LazySeq.java:40)
at clojure.lang.LazySeq.seq(LazySeq.java:49)
at clojure.lang.RT.seq(RT.java:521)
at clojure.lang.RT.nthFrom(RT.java:938)
at clojure.lang.RT.nth(RT.java:897)
at clojure.core$distinct$step__5304$fn__5305$fn__5307.invoke(core.clj:4848)
at clojure.core$distinct$step__5304$fn__5305.invoke(core.clj:4848)
at clojure.lang.LazySeq.sval(LazySeq.java:40)
at clojure.lang.LazySeq.seq(LazySeq.java:49)
at clojure.lang.RT.seq(RT.java:521)
at clojure.core$seq__4360.invokeStatic(core.clj:137)
at clojure.core$seq__4360.invoke(core.clj:137)
at clojure.core$reduce1.invokeStatic(core.clj:920)
at clojure.core$reduce1.invoke(core.clj:912)
at clojure.core$set.invokeStatic(core.clj:3986)
at clojure.core$set.invoke(core.clj:3977)
in other words, it implements IFn, just not the particular one that's being asked about. depends on your classloader hierarchy / environment
the code is doing a filter over a map, some very simple code. We have some custom classloader stuff so I guess I need to go chase down why it's loading things in the wrong order or whatever. Thank you both very much!
In the #beginners channel, people have opted in to help folks who are new to Clojure in depth. Questions in this channel tend to get answers that assume a fair bit of Clojure knowledge -- so you're going to get better help in #beginners