Fork me on GitHub
#clojure
<
2021-12-27
>
Eugen00:12:25

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

emccue00:12:10

proxy+ might be good enough?

emccue00:12:06

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

Eugen00:12:47

thanks, I will try it out. Glad I asked 🙂 . Sometimes I find it silly to ask / complain about things.

Eugen16:12:42

peoxy-plus doesn't work for me so far. I can't add custom methods and can't implement clojure protocols either

Eugen16:12:52

added some issues there

ghadi00:12:57

sometimes pain is good

ghadi00:12:08

I kid @U011NGC5FFY . You should add your usecase to that ask question

ghadi00:12:44

(e.g. Which class/library you are trying to extend)

Kevin Depue04:12:13

Hey folks, dropped a line into #clojurescript, I’m new to this Slack server so I’m not sure how active it is

lsenjov05:12:31

It's quieter because it's Christmas time, generally it's very active

Kevin Depue05:12:36

ah makes sense 🙂

Kevin Depue05:12:47

I’m a bit stuck trying to get figwheel working, just the blank project

lsenjov05:12:22

I'd help, but I only know shadow-cljs

Gerome07:12:09

Hello, how do you usually deal with thread-first expressions that turn into a collection e.g. (-> "2021-12-27" (clojure.string/split #"-")).

Gerome07:12:46

That is, if you then want to, say, map over the resulting collection?

Gerome07:12:27

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.

Jens07:12:55

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 %))))

Gerome07:12:27

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))

fearnoeval07:12:24

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.

💡 1
gratitude-thank-you 1
Gerome08:12:57

I've used it before but I forgot about it. It solves the problem nicely. Thanks!

👍 1
pavlosmelissinos08:12:58

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.

🎯 1
Carlo09:12:55

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 clojure

Carlo09:12:32

Ah, I needed set-resource-path!. Never mind 🙂

chrisn14:12:58

I 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?

emccue15:12:26

> 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?

chrisn15:12:40

duplicate versions of dtype-next that will have version conflicts.

emccue17:12:00

would all those issues be resolved if you made the api via Clojure interop from java and including the lib directly?

emccue18:12:46

or is part of the conceit that from java you would want the AOT version because performance

chrisn18:12:20

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.

chrisn20:12:10

Good news - they don't care about startup times :-). I will go the suggested route, thanks.

emccue20:12:43

lmk if you need another pair of eyes on this - i spend way too much time in java

chrisn16:12:55

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.

chrisn16:12:34

Or perhaps just barely non-trivial. We are still testing to figure out the real overhead.

emccue16:12:36

if you do not cache the var lookups. Caching the var lookups is i think what the clojure compiler does

chrisn17:12:11

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.

chrisn14:12:27

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.

zendevil.eth14:12:54

what’s the best way to check whether a string contains an uppercase character?

Lennart Buit14:12:44

Something like this:

(boolean (some #(Character/isUpperCase %) "my-string"))

ghaskins14:12:50

can always use a regex, too

ghaskins14:12:53

(some? (re-find #"[A-Z]" "Hello"))
=> true
(some? (re-find #"[A-Z]" "hello"))
=> false

Lennart Buit14:12:52

Depending on what definition of uppercase you are interested in 😉

Lennart Buit14:12:28

I think java does unicode uppercase, so that would be much more than A-Z

ghaskins14:12:57

fair, though what I really meant was <insert the re you want here>

ghaskins14:12:50

the OP didnt really give many requirements

Lennart Buit14:12:21

haha thats right 🙂.

zendevil.eth14:12:11

I’m using:

(not (empty? (clojure.set/intersection 
                        (set (map char (range (int \A) (inc (int \Z)))))
                        pass-set)))

ghaskins14:12:59

That should work. It’s less concise and may not perform as well, but not sure either of those matter for your app

ghaskins14:12:06

(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

ghaskins14:12:37

To @UDF11HLKC point, you may need more sophistication than the simple #“[A-Z]”

ghaskins14:12:00

though your example indicates that seems to be what you are after

ghaskins15:12:27

taking the sets out of the loop improves things a little

ghaskins15:12:28

(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

ghaskins15:12:50

but its still about 8x slower than regex

rutledgepaulv15:12:21

(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

zendevil.eth15:12:00

what if I want to check if the string contains lowercase?

zendevil.eth15:12:19

(defn has-lower? [s]
  (not= s (clojure.string/upper-case s)))
would be correct?

zendevil.eth15:12:08

what if I want to check for special characters?

zendevil.eth15:12:26

(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))))))
 

rutledgepaulv15:12:13

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

rutledgepaulv15:12:48

> Verifiers SHOULD NOT impose other composition rules (e.g., requiring mixtures of different character types or prohibiting consecutively repeated characters) for memorized secrets

Eugen19:12:08

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 .

noisesmith20:12:34

in your example there are two spellings in the package inerface and interface - do they match in your real code?

noisesmith20:12:16

also you shouldn't need to specify the whole package name, it should be in scope in the ns where it is declared automatically

noisesmith20:12:12

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)

Eugen21:12:21

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.

Eugen21:12:44

I think now it's fixed, thanks for looking at this and confirming I don't need AOT

dpsutton20:12:15

Has anyone seen the following error message before?

seancorfield21:12:59

Sounds like conflicting versions of libraries that were AOT'd. I think whitespace? was a recent-ish addition?

dpsutton21:12:51

i checked and i’m seeing it since 2017

seancorfield21:12:06

2013. Not recent-ish. But it could still be an old version of reader somewhere?

dpsutton21:12:34

yeah. that makes the most sense. oddly enough this started failing on a non-code change. it really doesn’t make sense

dpsutton21:12:11

and super frustratingly passes on test re-run

seancorfield21:12:51

Leiningen or CLI?

seancorfield21:12:58

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.

seancorfield21:12:01

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...

👍 1
hiredman04:12:48

Could be a code loading race, manifests in weird ways like that, and nondeterministic

hiredman04:12:44

There was a known code loading race in cli, but the most recent release is supposed to fix it

dpsutton05:12:34

i bumped that and hopefully it goes away. I don't like that I cannot explain it though, and that it is transient

hiredman06:12:36

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)