Fork me on GitHub
#clojure
<
2020-07-02
>
zackteo11:07:43

Hi guys, I tried searching everywhere but what unicode encoding in Clojure using? It doesn't seem to be UTF-8

hiredman11:07:31

Clojure reads in source files as utf8, jvm characters are internally utf16, other io on the jvm if you don't explicitly specify an encoding will use an os dependent default

andy.fingerhut11:07:08

Since Java 9, at least Hotspot, and perhaps other JVMs, use 8-bit characters for strings that contain only code points in the range [0, 127], as a space optimization.

hiredman15:07:37

Yes, but the exposed interface is still utf16

eskos11:07:55

Java/JVM also defaults to Big Endian (“network byte order”) everywhere it can and no BOM is used.

Alex Miller (Clojure team)13:07:55

in general, Clojure relies on the host (Java) and does what Java does wrt char encodings

Alex Miller (Clojure team)13:07:11

different apis and libs usually depend either on your default encoding or UTF-8 if you don't override. You can see default encoding with (System/getProperty "file.encoding")

zackteo14:07:16

Alright Thank you! (I figured out what I was looking for. Or rather I think my eyes had been playing tricks on me)

Alex Miller (Clojure team)13:07:27

the version of unicode is totally dependent on the jvm version you're using

hamled14:07:05

Hi, I'd like to better understand the difference between how a recursive function using lazy-seq differs from what for returns. My experience is that with lazy sequence returned by for is that when iterating it with loop the portion of the sequence that gets evaluated remains referenced in some way, so that none of the elements from previous iterations are garbage collected. This is assuming the application's iteration code doesn't involve retaining a reference, of course. I've got some example code that shows the difference through causing an OOM in the for case. https://gist.github.com/Hamled/cab41245abd208b4f6cb67026f135e34 (The gist also has some examples of how this interacts weirdly with futures from the manifold library, in case anyone has used that and has some insights... that's more representative of my actual use case.)

hamled14:07:51

Oh maybe this is a result of for using chunk-cons ? When I change the parameters of my example code so that the sequence is 100 elements long, but the total amount of memory allocated is still the same, the for version also works. I guess if the amount of memory needed for all entries in single chunk is more than can be allocated, then it OOMs?

noisesmith14:07:03

to be clear, for is not a loop and doesn't use looping internally - it is built out of "recursive" calls that are lifted out via lambda encapsulation

noisesmith14:07:24

IOW exactly how you'd use lazy-seq and self calls in any other lazy function you construct

noisesmith14:07:11

for, or a lazy-seq, only causes OOM if you are irresponsible about holding the return values and preventing GC (outside pathological cases where a single element blows the RAM)

noisesmith14:07:11

by binding the result of for in a top level def, you ensure that the vm's GC can never reclaim any value used in the lazy seq it generates, that is the source of your OOM and the answer is to never do that apologies - clearly I'm not fully awake yet, you were using for in defn, not def, so that isn't the issue

noisesmith14:07:32

(you'd get the same problem, but faster, if you used loop to build the equivalent non-lazy list)

noisesmith14:07:26

This classic blog post (about concat) describes so gotchas with lazy-seqs and imperative code. I think with a slight change of perspective it can also offer some insight about using resource-intensive or side effecting functions inside lazy code https://stuartsierra.com/2015/04/26/clojure-donts-concat

hamled15:07:17

Yeah the issue here is definitely that the design of my code is resulting in a reference to the head of the lazy sequence. I have some code that produces a sequence of messages representing server responses for a TCP server, and another layer that calls that code and puts each message into the stream representing the socket. To best separate these layers I was hoping to just return a lazy sequence in the one case where I have a lot of messages, but it seems like I cannot implement some code that iterates that lazy sequence without ultimately keeping the entire thing in memory.

noisesmith15:07:17

there are ways to do it carefully, but I think the simplest thing is not to use laziness when you need precise control of resource usage

noisesmith15:07:30

core.async is often used incorrectly or for the wrong things, but backpressure on execution to control resource utilization is something it can do well (though manifold which you are using already can arguably do that even better...)

hamled15:07:02

Yeah, I think that's what I assumed was happening with the design I had previously. It was working fine until I changed something to actually wait on the final result of putting all the messages into the stream.

hamled16:07:57

So my solution now involves providing a function that can be iteratively called to produce the next message to put into the stream. This seems to be working great, and I think it's an acceptable design (really I was just hoping to keep stream-related concepts out of the business logic). I am curious though, you mentioned it would possibly have been possible to use a lazy sequence if it was carefully done. Do you have any suggestions on stuff I could read to understand how that might have worked? Thanks again for the help!

Alex Miller (Clojure team)14:07:40

in general, I would not use lazy seqs to do things over a buffer, I would use loop/recur to have better control over when things happen

Alex Miller (Clojure team)14:07:06

with lazy seqs, you give up control over when realization happens (chunking usually happens in chunks of 32)

mv15:07:35

Has anyone written a plugin for JetBrains/Intellij in Clojure, or know of any resources/tutorials by people who have?

noisesmith15:07:08

yes, it's called Cursive, discussed in #cursive

mv15:07:37

I mean, I want to write a plugin for JetBrains in clojure, not necessarily for Clojure

eskos16:07:26

Tangential, but there's also Clojure-Kit for IDEA which seems to work for those people who can't deal with Cursive...highly subjective and I have no idea why, but there's an option 🙂

mv16:07:02

clojure-kit is open source, but written in kotlin/java

eskos16:07:36

Yup, by one of JetBrains' own employees.

borkdude16:07:12

I've tried it once when figuring out if clj-kondo could work together with it (it did)

sandbags17:07:54

Using the tick library I'm not seeing a better way to determine whether something is a date-time than testing for instance of either java.time.Instant or java.time.LocalDate. Am I missing anything?

noisesmith17:07:31

(ins)user=> (set/intersection (supers java.time.Instant) (supers java.time.LocalDate))
#{java.time.temporal.TemporalAdjuster java.time.temporal.TemporalAccessor java.io.Serializable java.time.temporal.Temporal java.lang.Object java.lang.Comparable}

noisesmith17:07:16

I don't know all the libs and classes in play here intimately, but usually the interface or superclass you want would be in that set

noisesmith17:07:37

java.time.temporal.Temporal smells correct

ghadi17:07:50

date-time is an artificial construct of that library

henryw37417:07:54

It is a localdatetime. Fair point about wrappers though. I often just use https://github.com/henryw374/cljc.java-time if I'm not so familiar with some part of the api and move to tick once I know what I'm doing and want some sugar.

ghadi17:07:05

not sure what its semantics are

ghadi17:07:28

is it a Instant LocalDate LocalDateTime ZonedDateTime OffsetDateTime ?

ghadi17:07:26

(This is primarily why I don't use wrappers for java.time, and prefer interop. Libraries seem to invent terminology without carefully understanding the stuff they wrap)

sandbags17:07:46

thanks. i guess i was more wondering if I was missing some kind of predicate like time? or date? so that i don't reinvent

henryw37417:07:52

Cljc.java-time has those preds. Tick has them on master but as yet unreleased

sandbags17:07:59

I'm in the world of checking classes … but thanks for the pointer to Temporal, I'm not sure I would have thought to go hunting for the base class

noisesmith17:07:48

the real problem is many wrapper library authors don't think of that either, the best thing as @ghadi says is to not use a wrapper, or just check what the library is using (which is often disappointing, I agree)

noisesmith17:07:16

but maybe you try the superclass it works and you can move on

sandbags17:07:29

actually i probably don't need a wrapper … i'm just potentially passing dates/times around from a database and doing some comparisons

sandbags17:07:40

so conversion to SQL compatible datetime is probably more important

kwladyka20:07:09

How do you run tests in shell for reflections with deps.edn? I would like to fail build when code has reflections.

kwladyka20:07:24

thanks, I would like to see in README what check check 🙂 It is a little mysterious 🙂

kwladyka20:07:00

Is it checking formatting? I don’t want to fail build when formatting is not as clj-check wants it

seancorfield20:07:01

lein help check -> Check syntax and warn on reflection.

Derek20:07:08

As far as I recall, it just checks for reflection warnings (https://github.com/athos/clj-check/blob/master/src/clj_check/check.clj#L14-L15)

Derek20:07:22

Though, it may check within your libraries code as well

kwladyka20:07:25

thank you, I will try this lib

seancorfield21:07:35

You'll want to check that you get a non-zero exit code for reflection warnings -- it may only give a non-zero exit code for compilation failures.

seancorfield21:07:52

Ah, it does not:

(! 773)-> clojure -A:check
Compiling namespace check.example
Reflection warning, check/example.clj:7:3 - call to method append on java.lang.String can't be resolved (no such method).

Thu Jul 02 14:06:26
(sean)-(jobs:0)-(~/clojure/example)
(! 774)-> echo $?
0
So it won't fail the build for you.

kwladyka21:07:22

it also hang forever

clj -Acheck
Jul 02, 2020 11:05:38 PM api.core invoke
INFO: app start K_REVISION: nil
Jul 02, 2020 11:05:38 PM api.core invoke
WARNING: HOST variable is not set!

kwladyka21:07:14

Do we have other alternatives to check reflections?

kwladyka21:07:09

It looks like it not only load namespaces but also run main functions so start the server

kwladyka21:07:20

ring is started so process never exit

seancorfield21:07:21

No, it only loads namespaces.

kwladyka21:07:39

so why hang forever?

seancorfield21:07:39

So you must be doing something in a def form that causes your server to start.

seancorfield21:07:16

I bet you do. There's nothing in clj-check that runs any functions. It just loads files.

kwladyka21:07:25

so maybe server not start but check never end

seancorfield21:07:45

Nope. check works just fine. The problem is in your code.

seancorfield21:07:53

Wait for 60 seconds and see if it exits. You may be starting thread processes just by loading namespaces, and clj-check does not include shutdown-agents so it will wait for threads to cleanly shutdown, instead of just exiting.

Derek21:07:54

Should be easy enough to add. The author was quite receptive when last contacted

kwladyka21:07:57

:check {:extra-deps {athos/clj-check {:git/url ""
                                                 :sha "b48d4e7000586529f81c1e29069b503b57259514"}}
                   :main-opts ["-m" "api.core"]}
README show I should use main-opts and I am 99,9% sure it runs main functions, because I see (l/info "app start K_REVISION:" (System/getenv "K_REVISION"))

Derek21:07:31

You should be using clj-check’s main-opts

seancorfield21:07:36

No, the readme has this

:main-opts ["-m" "clj-check.check"]}}

kwladyka21:07:45

with this it doesn’t work for me

seancorfield21:07:47

YOU are running your own main function

seancorfield21:07:01

Define "doesn't work".

kwladyka21:07:06

Compiling namespace spec.utils
Compiling namespace spec.common
Execution error (FileNotFoundException) at clj-check.check/check-ns (check.clj:15).
Could not locate clojure/test/check/generators__init.class, clojure/test/check/generators.clj or clojure/test/check/generators.cljc on classpath.

seancorfield21:07:14

(! 767)-> clj -A:new app check/example
Downloading: seancorfield/clj-new/maven-metadata.xml from clojars
Generating a project called example based on the 'app' template.

Thu Jul 02 14:05:28
(sean)-(jobs:0)-(~/clojure)
(! 768)-> cd example/

Thu Jul 02 14:05:30
(sean)-(jobs:0)-(~/clojure/example)
(! 769)-> clojure -A:check
Compiling namespace check.example

Thu Jul 02 14:05:39
(sean)-(jobs:0)-(~/clojure/example)
(! 770)-> vi src/check/example.clj 

Thu Jul 02 14:06:11
(sean)-(jobs:0)-(~/clojure/example)
(! 771)-> clojure -A:check
Compiling namespace check.example
Reflection warning, check/example.clj:7:3 - call to method append on java.lang.String can't be resolved (no such method).
(I added (.append "Hello" "World") in vi to force a reflection warning)

seancorfield21:07:02

@U0WL6FA77 Your output shows it is working perfectly.

seancorfield21:07:17

You forgot to provide aliases to add the dependencies you need.

seancorfield21:07:16

I expect your spec.common namespace is requiring clojure.test.check and you didn't have -A:test to add that dependency?

kwladyka21:07:25

oh true… I tried to add test but probably I made a typo or something

kwladyka21:07:40

I have this feeling in this month I have stupid issues here on Clojurians channel

kwladyka21:07:43

I need holidayś 🙂

seancorfield21:07:10

You need to be more methodical and take more careful steps when you are debugging.

kwladyka21:07:21

I know this is bad explanation, but I am really tired, because of some private reasons. But I am going on holidays in July so I will recover 🙂

kwladyka21:07:59

I am just half brain now or call it however you want 🙂

seancorfield21:07:56

Enjoy your vacation! Definitely sounds like you need it! Unwind, and come back refreshed.

kwladyka21:07:24

I truly need. Thank you.

seancorfield21:07:07

Once you get this figured out, you could run clojure -A:check 2>&1 > check.log and if there are compilation errors, that should fail the build, then do fgrep -v Compiling check.log | fgrep -v Reflection which should have a zero status if there are no reflection warnings, and a status of 1 if there are -- which should fail the build (assuming it fails on any non-zero exit status for any command)

👍 3
kwladyka21:07:57

Reflection warning, bidi/bidi.cljc:20:31 - call to static method decode on java.net.URLDecoder can't be resolved (argument types: java.lang.String, unknown).
Oh I guess I can’t really fail, because of dependencies reflections which I can’t change

Derek21:07:46

you can always grep for your project namespaces

kwladyka21:07:48

this is true, but solution start to be complex and prone to errors

kwladyka21:07:05

I will try it and will see

datran21:07:27

I've started playing with https://github.com/gnl/ghostwheel, and I like it so far, except that my clojure-mode in emacs doesn't indent it like defn. Does anybody know how to fix that?

phronmophobic21:07:47

you can try editing the clojure mode variable clojure-defun-indents by putting (put-clojure-indent 'some-symbol :defn) in you .emacs

phronmophobic21:07:02

presumably (put-clojure-indent '>defn :defn) based on your link

datran21:07:13

Perfect, that works wonderfully. I'll just tuck that in my .dir-locals file

parrot 3
datran21:07:49

I'm not sure if it's a library problem or an emacs problem

nikolavojicic22:07:29

Are entries of map literals evaluated in order? E.g. is it guaranteed that delete! will occur before insert! ?

{:del (delete! ,,,)
 :ins (insert! ,,,)}

noisesmith22:07:26

clojure is always evaluated left to right, but putting side effects in map entries is just weird - I'd expect that to work but use let anyway for clarity

noisesmith22:07:19

oh! - the reader constructs the map before the resulting form is evaluated, so I think it could reorder (testing...)

Jan K22:07:46

"Vector elements are evaluated left to right, Sets and Maps are evaluated in an undefined order."

👍 3
noisesmith22:07:45

@nikolavojicic @jkr.sw yeah - the reader reorders before the side effects happen

user=> {:a (println "a") :b (println "b") :c (println "c") :d (println "d") :e (println "e") :f (println "f") :g (println "g") :h (println "h") :i (println "i") :j (println "j") :k (println "k") :l (println "l") :m (println "m") :n (println "n") :o (println "o") :p (println "p") :q (println "q") :r (println "r") :s (println "s") :t (println "t") :u (println "u") :v (println "v") :w (println "w") :x (println "x") :y (println "y") :z (println "z")}
y
q
r
v
o
n...

👍 3
henryw37417:07:52

Cljc.java-time has those preds. Tick has them on master but as yet unreleased

henryw37417:07:54

It is a localdatetime. Fair point about wrappers though. I often just use https://github.com/henryw374/cljc.java-time if I'm not so familiar with some part of the api and move to tick once I know what I'm doing and want some sugar.