This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-12-16
Channels
- # adventofcode (36)
- # announcements (30)
- # babashka (1)
- # beginners (161)
- # boot-dev (2)
- # bristol-clojurians (3)
- # clj-kondo (10)
- # clojure (125)
- # clojure-europe (10)
- # clojure-italy (4)
- # clojure-nl (7)
- # clojure-spec (1)
- # clojure-uk (26)
- # clojuredesign-podcast (3)
- # clojurescript (13)
- # core-async (5)
- # cryogen (3)
- # cursive (134)
- # data-science (8)
- # datascript (3)
- # datomic (32)
- # fulcro (24)
- # graalvm (2)
- # joker (5)
- # leiningen (5)
- # malli (18)
- # off-topic (14)
- # pathom (4)
- # re-frame (3)
- # reagent (11)
- # remote-jobs (3)
- # rewrite-clj (8)
- # shadow-cljs (47)
- # spacemacs (3)
- # sql (12)
- # vim (6)
@seancorfield will do
I’ve encountered a weird issue - when serializing booleans with normal
means, false
comes back as… truthy
it seems to be because Clojure is essentially asking, “are you the same object as Boolean/FALSE
or are you null? if not, you’re truthy my friend!”
and when deserializing false
, it comes out as not the exact same object as Boolean/FALSE
but rather a new instance of Boolean - therefore, truthy
@Brandon that is what is happening. Well known issue for Java, too. Don't use the Boolean constructor to create Boolean values: https://clojuredocs.org/clojure.core/if
@andy.fingerhut this seems like a subtle bug in clojure itself, no? Though it is bad style to construct new Booleans, sometimes it’s out of one’s control. I would expect Clojure to at least support evaluating Booleans’ truthiness by value in this case
If it is a bug in Clojure, then it is a bug in Java, too. I believe Java devs are advised not to do this, too.
You can use (boolean x)
to convert a new'd Boolean to Boolean/TRUE
or Boolean/FALSE
I believe.
(at least, I have half a recollection Java if
works the same way. I believe I did that experiment when writing the page of docs I linked to above)
user=> (if (Boolean. false) :truthy :falsey)
:truthy
user=> (if (boolean (Boolean. false)) :truthy :falsey)
:falsey
It seems to me that one could consider this a bug in the serialize/deserialize code.
I tried on http://repl.it and it seems to work as expected
public static void main() {
if (new Boolean(false)) {
System.out.println("Hello, world!");
} else {
System.out.println("Goodbye, world!");
}
}
outputs "Goodbye, world!"Strange to me: @alexmiller mentioned something recently that "default serialization" should do the right thing with Java booleans, and only "clever" things should have trouble. I do not know whether
is something he would consider default or "clever"
@vale I tried compiling a similar one-class Java source file using AdoptOpenJDK 11, and got this message:
$ javac -Xlint:deprecation MyA.java
MyA.java:3: warning: [deprecation] Boolean(boolean) in Boolean has been deprecated
if (new Boolean(false)) {
^
1 warning
No such warning with AdoptOpenJDK 8, so must have been deprecated some time between there.
Since Java 9, according to JavaDoc page for Java 11: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Boolean.html
Boolean(boolean x) was deprecated (apparently) in 9 and http://repl.it runs on 10 so it's still working
Deprecated could continue working indefinitely in Java, given desire for backwards compatibility.
Not removed in Java 11. Only gives a warning.
Still in Java 13, still deprecated
How does dependency resolution works in clj
when supplying aliases? I though aliases were additive:
clj -A:test -e "(require 'next.jdbc)" ;;OK
clj -Atest:benchmark -e "(require 'next.jdbc)" ;; Syntax error (ClassNotFoundException) compiling at (clj_lx/benchmark.clj:2:3).
@U07S8JGF7 I assume you mean "don't use it for caching functions that accept objects (like connections)"?
memoize
only cares about the arguments, not the return value, but I see what you mean.
Well, not a memory leak, but you get the same connection object back, over and over again 🙂
user=> (defn f [url] (.openConnection (.URL. url)))
#'user/f
user=> (def ff (memoize f))
#'user/ff
user=> (def a (ff ""))
#'user/a
user=> (def b (ff ""))
#'user/b
user=> (identical? a b)
true
user=>
Ah, you're saying that if the def
of ff
happened concurrently in multiple threads, you'd have a problem?
That's why Clojure 1.10 has a serialized require -- for thread safe requiring of namespaces 🙂
(with a plan to make the regular require
thread safe too)
'k ... does clojure.core.memoize
suffer from the same race condition I wonder?
Of course, that question is complicated by the fact that c.c.m. supports more that just a "basic" cache: it supports TTL, LRU, etc, etc.
Well, if you have a TTL cache behind it, even if it were thread safe, you'd get a stream of unique objects returned over time anyway...
That was exactly the problem, I wanted to return / produce identical objects, but memoize isn’t suited for this
your initial question is a bit off in that sense ... yes it's thread safe (execution from parallel threads breaks nothing)
but as i see it https://github.com/clojure/clojure/blob/clojure-1.9.0/src/clj/clojure/core.clj#L6263 , it can easily call the actual data source twice
or even more, depending on how good you are at creating that race condition 😄
@borkdude Do you have a context where you wish that something like memoize never ran the source function twice with the same arguments?
@andy.fingerhut yeah, I need to have a unique object for a given key, so I don't want to have to non-identical objects for the same key
the scenario I have is that we have multiple scheduled jobs running, but I don't want more than once instance of them running at the same time
so I create a unique ReentrantLock
object for each job (by name) which is then tried to acquire at the beginning of a job's body
and using memoize for that is probably not a good idea, so that's why I reverted to locking
for now
I occasionally remember that clojure.lang.PersistentQueue
exists, but it doesn't seem to have any documentation. Is that an implementation detail of Clojure that should be avoided? Does anyone know why there isn't any documentation?
Clojure's persistent queues are mentioned in the Clojure cheat sheet, separately from the more commonly used ones: https://clojure.org/api/cheatsheet It does not have a named constructor function the way the others do, for which there is an open ticket, but I think they are not mentioned as much because of their more limited applicability. There is no reason to avoid them that I know of.
Queues are not emphasized because most (but not all!) interesting uses of a queue are in concurrent code. Persistent queues are not (by themselves) useful in this way as they don't have identity - modifications return a new queue so multiple threads can't see a change unless you pair it with something stateful like an atom. So in general, I find the scenarios where queues are useful to be small (tree/graph traversal loops are one place where they are).
For the more common case of a concurrent queue, I'd recommend either core.async channels or the existing Java concurrent queue impls in the JDK as being a better solution.
ClojureScript does have more support for queues and I think some aspects of that are worth pulling over to Clojure as portable calls (constructor, predicate fns), but I don't think the literal stuff is worth doing in Clojure. Just my own opinions...
Does anyone here know what “Estimated” means with java heap sizes: e.g.
java -XshowSettings -version
VM settings:
Max. Heap Size (Estimated): 3.56G
Ergonomics Machine Class: server
Using VM: Java HotSpot(TM) 64-Bit Server VM
Yet:
java -XshowSettings -Xmx2g -version
VM settings:
Max. Heap Size: 2.00G
Ergonomics Machine Class: server
Using VM: Java HotSpot(TM) 64-Bit Server VM
Why is it estimated? I know the JVM will calculate the default to be 1/4 available ram… At first I thought it was estimated because it hasn’t actually claimed it; however it’s also not claimed it in the second case; right?
isn't it just an indicator of the automatic ~25% of available ram ?
wouldn’t that imply the second should also be an estimate though?
my machine tells me 5.5g estimated , which roughly is around the 25% mark
the second one you specified
I did — but it still might not be available when it needs it.
well for that in the old days we did -Xms
I know — and some of us still do 🙂
I’m just curious about the choice of words there
I don’t see how it’s an estimate.
i.e. I one might expect “Estimated” to only disappear only when -Xms
was set to the same value as -Xmx
i think it's meant that "jvm estimated that you need 25% of the ram"
ok I guess that makes sense… was just wondering if there was something else going on.
Does anyone have experience with serf / zookeeper / etcd
similar tools? Examples seems to show that you run them on a node/machine and manage the cluster that way.
Can I bound them to my apps or somehow watch specific apps on a single machine, so they exit when the exits etc.? Say I have 2 apps on a single machine and want to monitor their status via these tools, possible/stupid ?
I guess you could create ephemeral node that would die if your app exits with Zookeeper
but I'm not sure. With other tools, you could run their agents and constantly check top
to see if your app alive and send events via their agents?
for zookeeper at least, it considers your client gone if you are stale, which means if your app exits / machine crashes / code locks up or hard loops,, zookeeper just decides you no longer exist
which is the right thing for its domain logic
in zookeeper an "ephemeral node" is in fact a data storage location that promises to delete itself if your client isn't actively connected to the cluster
your own app is not part of the zookeeper cluster
oh wait - are you asking for in-process zk or similar? that's not a thing with zookeeper, it's incompatible with the premise
Only tool I'm aware of that can be embedded in a JVM app is jgroups http://www.jgroups.org
@cakir-enes what are your trying to achieve?
Most distributed consistent stores (etcd, zookeeper) require a stable quorum membership, and have a higher communication overhead per member of the quorum, so trying the lifetime of those processes to app processes doesn't make sense
yeah it really doesnt, but the thing is if I deploy one of those agents to a machine then deploy several apps on that machine how do I watch the apps and talk to other agents about their status? Like when this app goes down spin up new one with this cmd and do this etc
That sounds an awful lot like Nomad or a system built on top of Consul, both HashiCorp tools: https://www.consul.io https://www.nomadproject.io
Make apps log to /tmp/somefile.log
then watch that file and send event abc didnt respond for 5 sec
via serf
agent is a bad idea?
how do I set the input for grep here:
(require '[ :as io])
(def grep (-> (ProcessBuilder. ["grep" "hello"])
(.inheritIO)
(.start)))
(def grep-input (.getOutputStream grep))
(binding [*out* (io/writer grep-input)]
(println "hello")
(println "bye"))
(.waitFor grep)
yeah you want redirectInput to be set to Redirect.PIPE not Redirect.INHERIT, then .getOutputStream will work
you can still keep Redirect.INHERIT for the redirectOutput and redirectError https://docs.oracle.com/javase/7/docs/api/java/lang/ProcessBuilder.html#inheritIO()
I did this now and it worked:
#!/usr/bin/env bb
(require '[ :as io])
(def grep (-> (ProcessBuilder. ["grep" "hello"])
(.start)))
(def grep-input (.getOutputStream grep))
(def grep-output (.getInputStream grep))
(binding [*out* (io/writer grep-input)]
(println "hello")
(println "bye"))
(.close grep-input)
(.waitFor grep)
(prn (slurp grep-output))
if you want the output/error to go to your processes output I would do
(-> (ProcessBuilder. ...)
(.redirectOutput Redirect/INHERIT)
(.redirectError Redirect/INHERIT)
(.start))
Not generally.