This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-12-27
Channels
- # adventofcode (1)
- # announcements (16)
- # babashka (16)
- # beginners (59)
- # calva (13)
- # clj-kondo (7)
- # clj-on-windows (3)
- # cljdoc (5)
- # clojure (85)
- # clojure-dev (5)
- # clojure-europe (4)
- # clojured (3)
- # clojurescript (87)
- # cursive (12)
- # emacs (4)
- # fulcro (15)
- # gratitude (1)
- # introduce-yourself (4)
- # malli (7)
- # off-topic (5)
- # polylith (6)
- # re-frame (15)
- # reagent (2)
- # shadow-cljs (5)
- # tools-deps (6)
- # web-security (2)
- # xtdb (5)
would love to see this (or similar solution) in Clojure - I think working with java abstract classes is quite painfull https://ask.clojure.org/index.php/3360/support-abstract-base-classes-with-java-only-variant-reify
but also there is no reason something like this needs to be a language feature - its just a library that would be a bit involved to write
thanks, I will try it out. Glad I asked 🙂 . Sometimes I find it silly to ask / complain about things.
peoxy-plus doesn't work for me so far. I can't add custom methods and can't implement clojure protocols either
I kid @U011NGC5FFY . You should add your usecase to that ask question
Hey folks, dropped a line into #clojurescript, I’m new to this Slack server so I’m not sure how active it is
ah makes sense 🙂
I’m a bit stuck trying to get figwheel working, just the blank project
Hello, how do you usually deal with thread-first expressions that turn into a collection e.g. (-> "2021-12-27" (clojure.string/split #"-"))
.
I've used something like (-> "2021-12-27" (clojure.string/split #"-") (->> (map js/parseInt)))
before but I've been told it's bad style because it's difficult to read.
I used let to organize it. But don't know if that is any better. For example
(let [split-date (-> "2021-12-27" (clojure.string/split #"-"))]
(->> split-date
(map #(Integer/parseInt %))))
Hm, yes it's a little more explicit because it doesn't omit split-date
and %
but there's so much more noise than in (-> "2021-12-27" (split #"-") (->> (map Integer/parseInt))
In the example stated, my personal preference would be like Jens', but with no threading macros at all. However, I understand that the example may be chopped down from a larger "real" example where that may not be as palatable. Since it wasn't mentioned yet, though, if you like thread-first and thread-last, you may like https://clojuredocs.org/clojure.core/as-%3E`as->`https://clojuredocs.org/clojure.core/as-%3E which lets you give a name to the value being threaded so you can "move" it at the cost of having to put the name on every call.
FWIW, ->
and as->
is a nice trick that I also use, e.g. when a map changes position across chained functions. However, going from a map to a collection (or vice versa) changes the semantics of the operation and that always makes me wonder if operating on the new data structure still belongs in the same expression.
Sometimes I might not factor out the part that is different but it usually feels like a concession.
I'm trying to use the selmer
template engine, and I have this call:
(s/render-file "template/template.hi" {:a "Carlo"})
which gives me a resource not found error:
resource-path for template/template.hi returned nil, typically means the file
doesn't exist in your classpath.
How should I think about this error? I'm not familiar with how classpath works in clojureI would like to release minimal java api's on a few clojure libraries such as libpython-clj, libjulia-clj, and potentially tech.ml.dataset via the gen-class method. These all rely on dtype-next and that means that if I am not careful they will all have dtype-next class files in them. If I produce an aot-compiled version of dtype-next and use that version for the dependency in the downstream projects will this work as expected meaning will the aot compilation system avoid re-creating the dtype-next's already aot'd classes when I aot the gen-class java interface?
> if I am not careful they will all have dtype-next class files in them And just to ask, what is the issue with that?
would all those issues be resolved if you made the api via Clojure interop from java and including the lib directly?
or is part of the conceit that from java you would want the AOT version because performance
Those issues would be solved with the api strategy and it means I am not releasing jars with AOT code in them which is also better. I am not certain how sensetive this person is to startup times but potentially not very. Will check with them.
Good news - they don't care about startup times :-). I will go the suggested route, thanks.
This bumped a performance test from 6 seconds to 14 seconds as it takes I guess 7 seconds on the test computer for Clojure to AOT compile libjulia-clj's main namespace. In addition we are seeing nontrivial per-call overhead for granular cases. So using the java api of Clojure introduces some nontrivial per-call overhead if you do not cache the var lookups.
Or perhaps just barely non-trivial. We are still testing to figure out the real overhead.
if you do not cache the var lookups.
Caching the var lookups is i think what the clojure compiler does
Its fine without for now. The overhead was small compared to the inter-language overhead. The startup time irritates me but that gets us back to AOT land and GraalNative is better fix overall.
To be clear this means that, for instance, libjulia-clj has two jars on clojars - one without aot that is meant for Clojure consumption and one with AOT that is meant for java consumption.
what’s the best way to check whether a string contains an uppercase character?
Something like this:
(boolean (some #(Character/isUpperCase %) "my-string"))
(some? (re-find #"[A-Z]" "Hello"))
=> true
(some? (re-find #"[A-Z]" "hello"))
=> false
Depending on what definition of uppercase you are interested in 😉
I think java does unicode uppercase, so that would be much more than A-Z
haha thats right 🙂.
I’m using:
(not (empty? (clojure.set/intersection
(set (map char (range (int \A) (inc (int \Z)))))
pass-set)))
That should work. It’s less concise and may not perform as well, but not sure either of those matter for your app
(criterium.core/quick-bench (not (empty? (clojure.set/intersection
(set (map char (range (int \A) (inc (int \Z)))))
(set "Hello")))))
Evaluation count : 115524 in 6 samples of 19254 calls.
Execution time mean : 5.380075 µs
Execution time std-deviation : 192.028942 ns
Execution time lower quantile : 5.195526 µs ( 2.5%)
Execution time upper quantile : 5.668781 µs (97.5%)
Overhead used : 5.945740 ns
Found 1 outliers in 6 samples (16.6667 %)
low-severe 1 (16.6667 %)
Variance from outliers : 13.8889 % Variance is moderately inflated by outliers
=> nil
(criterium.core/quick-bench (boolean (some #(Character/isUpperCase %) "Hello")))
Evaluation count : 166710 in 6 samples of 27785 calls.
Execution time mean : 4.691801 µs
Execution time std-deviation : 1.473038 µs
Execution time lower quantile : 3.643838 µs ( 2.5%)
Execution time upper quantile : 6.848259 µs (97.5%)
Overhead used : 5.945740 ns
=> nil
(criterium.core/quick-bench (some? (re-find #"[A-Z]" "Hello")))
Evaluation count : 8842668 in 6 samples of 1473778 calls.
Execution time mean : 95.217955 ns
Execution time std-deviation : 40.143411 ns
Execution time lower quantile : 63.578066 ns ( 2.5%)
Execution time upper quantile : 145.076806 ns (97.5%)
Overhead used : 5.945740 ns
=> nil
To @UDF11HLKC point, you may need more sophistication than the simple #“[A-Z]”
(def a-z (set (map char (range (int \A) (inc (int \Z))))))
=> #'user/a-z
(def pass-set (set "Hello"))
=> #'user/pass-set
(not (empty? (clojure.set/intersection
a-z pass-set)))
=> true
(criterium.core/quick-bench (not (empty? (clojure.set/intersection
a-z pass-set))))
Evaluation count : 757662 in 6 samples of 126277 calls.
Execution time mean : 794.342275 ns
Execution time std-deviation : 20.931468 ns
Execution time lower quantile : 779.791023 ns ( 2.5%)
Execution time upper quantile : 828.102107 ns (97.5%)
Overhead used : 5.945740 ns
Found 1 outliers in 6 samples (16.6667 %)
low-severe 1 (16.6667 %)
Variance from outliers : 13.8889 % Variance is moderately inflated by outliers
=> nil
(defn has-upper? [s]
(not= s (clojure.string/lower-case s)))
(criterium.core/quick-bench (has-upper? "my-string"))
Evaluation count : 32280036 in 6 samples of 5380006 calls.
Execution time mean : 12.746610 ns
Execution time std-deviation : 0.824987 ns
Execution time lower quantile : 12.230249 ns ( 2.5%)
Execution time upper quantile : 14.103503 ns (97.5%)
Overhead used : 5.950458 ns
Found 1 outliers in 6 samples (16.6667 %)
low-severe 1 (16.6667 %)
Variance from outliers : 14.9398 % Variance is moderately inflated by outliers
=> nil
what if I want to check if the string contains lowercase?
(defn has-lower? [s]
(not= s (clojure.string/upper-case s)))
would be correct?what if I want to check for special characters?
(defn is-pass-valid? [pass]
(let [pass-set (set pass)
range-set (fn [start end]
(set (map char (range (.charCodeAt start) (inc (.charCodeAt end))))))]
(and (>= (count pass) 8)
(not= pass (clojure.string/lower-case pass))
(not= pass (clojure.string/upper-case pass))
(not (empty? (clojure.set/intersection
(clojure.set/union
(range-set \space \/)
(range-set \: \@)
(range-set \[ \`)
(range-set \{ \~))
pass-set))))))
well, if you're checking to see if a password meets certain conditions, i would advise just reading modern password guidance which suggests you shouldn't require a bunch of hoops for someone to jump through because it inevitably leads them to using somewhat weak / predictable patterns in order to satiate the password validation algorithm
https://www.troyhunt.com/passwords-evolved-authentication-guidance-for-the-modern-era/
> Verifiers SHOULD NOT impose other composition rules (e.g., requiring mixtures of different character types or prohibiting consecutively repeated characters) for memorized secrets
do I need AOT compilation so I can use the clojure protocols interface ? I am trying to use proxy-plus with an abstract class and a protocol. I got the suggestion to use the interface of that protocol (which is what I was going for) - without success https://github.com/redplanetlabs/proxy-plus/issues/15 .
in your example there are two spellings in the package inerface
and interface
- do they match in your real code?
also you shouldn't need to specify the whole package name, it should be in scope in the ns where it is declared automatically
you don't need AOT for this, clojure creates an interface class when you use defprotocol
, and if you look at the error, it isn't even a proxy+ issue - it's the compiler telling you that the class you asked for does not exist (likely the typo mentioned above)
yes, it was the typo above. I had the protocol in the same file and it didn't work and then I moved it outside and introduced the typo.
Sounds like conflicting versions of libraries that were AOT'd. I think whitespace?
was a recent-ish addition?
2013. Not recent-ish. But it could still be an old version of reader somewhere?
yeah. that makes the most sense. oddly enough this started failing on a non-code change. it really doesn’t make sense
Leiningen or CLI?
Hmm, bit surprised it's non-deterministic then, although I guess your test deps could be bringing in a different tools.reader and changing what gets selected.
I'd definitely look through -Stree
and perhaps some of the JARs you're bringing in to see if there's an AOT'd tools.reader somewhere in them...
Could be a code loading race, manifests in weird ways like that, and nondeterministic
There was a known code loading race in cli, but the most recent release is supposed to fix it
i bumped that and hopefully it goes away. I don't like that I cannot explain it though, and that it is transient
https://ask.clojure.org/index.php/10905/control-transient-deps-that-compiled-assembled-into-uberjar has some stacktraces from the code loading race errors that look pretty similar to yours (random vars in tools.reader not existing)