This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-12-07
Channels
- # adventofcode (269)
- # beginners (100)
- # boot (6)
- # cider (4)
- # cljsrn (4)
- # clojure (161)
- # clojure-android (31)
- # clojure-argentina (2)
- # clojure-brasil (8)
- # clojure-greece (45)
- # clojure-india (2)
- # clojure-madison (2)
- # clojure-russia (17)
- # clojure-spec (4)
- # clojure-sweden (1)
- # clojure-uk (32)
- # clojurescript (93)
- # core-logic (2)
- # cursive (21)
- # data-science (2)
- # datomic (46)
- # defnpodcast (1)
- # duct (5)
- # emacs (21)
- # events (1)
- # fulcro (17)
- # graphql (13)
- # job (1)
- # jobs (2)
- # leiningen (11)
- # lumo (3)
- # off-topic (119)
- # om (4)
- # onyx (2)
- # planck (6)
- # portkey (12)
- # re-frame (5)
- # reagent (3)
- # ring (5)
- # shadow-cljs (27)
- # spacemacs (19)
- # specter (6)
- # unrepl (9)
@tacosundae If you knew in advance that you wanted to generate random elements from the same set many times, you could improve performance by creating a vector of the set elements one time, then calling rand-nth on that vector many times. That doesn't improve performance if you only want to do it once per set, though.
Is there going to be a state of Clojure survey this year?
Yeah, we may slip into the new year. Kind of focused on 1.9
(swap! some-atom func)
suppose func decides to throw an exception (i.e. it can't do the update), what is the proper way to signal this ?
@qqq throw the exception
i'm using an agent to queue tasks, and want to wait on the task to complete, what is the proper way to do this?
i'm now using this:
(let [p (promise)
a (agent 0)
task-fn (fn [x] (let [new-val (inc x)]
(deliver p new-val)
new-val))]
(send a task-fn)
@p)
but this delivers the promise before the task fn completes, so it not completely waterproof
@chrisblom you can't make waterproof assumptions on an agent deref
@chrisblom could you use core.async for this case ?
Use await
or await-for
i only need to wait until the submitted task completes, with await it would wait for all dispatched tasks
This is not correct. The docstring says “Blocks the current thread (indefinitely!) until all actions dispatched thus far, *from this thread or agent*, to the agent(s) have occurred.”
unless you really want this single task
in which case, agents are probably not a great solution. Just use a future
and wait for it to finish.
yeah, agents are not ideal, but i need to execute the tasks sequentially, one at a time, so futures will not do
if you’re only executing tasks one at a time and waiting for them to finish, then why are you using concurrency features at all?
to give you some context, i'm trying to solve this issue https://github.com/vvvvalvalval/datomock/issues/2
Found a solution: i can add watch, and pass the delayed deliver to it. As watches are called after the state is updated, this ensures that once the promise is delivered, the task has updated the agent state
(let [p (promise)
a (add-watch (agent {:x 0}) :force-deliver (fn [_ _ _ new-val] (force (:delayed-deliver new-val))))
task-fn (fn [{:keys [x]}]
(let [new-val (inc x)]
{:x new-val
:delayed-deliver (delay (deliver p new-val))}))]
(send a task-fn)
[@p @a])
I would like some advice about bytecode generation.
I have a java class with a public primitive int field I want to assign with set!
, however I can't manage to get rid of intermediate boxing no matter what I hint.
The decompiled bytecode for assignment is always something like :
((TheClass)the_instance).the_field = RT.intCast((Number)Numbers.num(value));
This looks suboptimal, I'm not sure the runtime is clever enough to bypass this kind of stuff. Am I missing something ?here is a minimal example https://gist.github.com/leonoel/b7e8e4b93e7d14fcbdd3fbdac4921223
Integer var10002 = Numbers.unchecked_int_inc(RT.intCast(0L));
var10000.field = RT.intCast((Number)var10002);
Integer var10002 = Numbers.unchecked_int_inc((int)0L);
var10000.field =
RT.uncheckedIntCast((Number)var10002);
what I want is to perform arithmetic operations on a primitive instance field and avoid boxing. Local bindings only, no vars involved
doesn't seem to be possible ATM. I'll take a look at the compiler this evening, should be an easy fix
you rock ! it's definitely a huge win for me, my benchmarks are almost on par with java with your patch.
@kgofhedgehogs you probably solved it already, but take a look at select*
instead of select
, it returns a query object that can easily be composed later
and then realized with exec
(select tbl
(where conditions)
(fields ...))
(-> (select* tbl)
(where conditions)
(fields ...))
you can put parts of queries in functions
(defn where-thing-active
[query]
(where query ({:expires [> (sqlfn :now)]
:deleted [= nil]})))
and then compose them easily like
(-> (my-base-select)
(where {:user_id user-id})
(cond-> only-active? where-thing-active
type (where {:type (-> type name upper-case)}))
exec))
I have a directory of files from a jar I'm using and I want to do some filtering before reading them. I would like to do:
(file-seq (io/resource "com/thejar/foo-directory"))
but I cannot because of a ClassCastException java.net.URL cannot be cast to java.io.File
things inside jars are not files
but io/resource should be returning a file url if the jar was extracted to disk
you can get a seq on the resources inside a jar if you prefer not to extract - just remember that File is never the general or abstract thing in the jvm - it’s specifically and only for entries in file systems
@noisesmith it looks like i can do something like (io/file (.getPath (io/resource ...)))
, yeah?
if it’s a file - but only if that file has been extracted to disk
:thumbsup:
@devn I don’t know how you’d get that error if it was on disk though
no, resource returns resource urls inside jars for things that are not extracted
user=> ( "config/development.clj")
#object[java.net.URL 0x74a744e9 "file:/Users/justin/sprinklr/peregrine/resources/config/development.clj"]
user=> ( ( "config/development.clj"))
#object[java.io.File 0x6cb513bc "/Users/justin/sprinklr/peregrine/resources/config/development.clj"]
- no error, because it is actually on diskthat error should mean that the url points to a thing inside a jar, which you can’t make a File out of
user=> (io/resource "models")
#object[java.net.URL 0x7f165eee "jar:file:/Users/me/.m2/repository/com/amazonaws/aws-java-sdk-models/1.11.244/aws-java-sdk-models-1.11.244.jar!/models"]
This is a directory containing a bunch of model files which I would like to iterate over
see, that’s something inside a jar
that’s what the ! there means
replicating your error:
user=> ( "clojure/core.clj")
#object[java.net.URL 0x3d6b1a48 "jar:file:/Users/justin/.m2/repository/org/clojure/clojure/1.8.0/clojure-1.8.0.jar!/clojure/core.clj"]
user=> ( ( "clojure/core.clj"))
IllegalArgumentException Not a file: jar:file:/Users/justin/.m2/repository/org/clojure/clojure/1.8.0/clojure-1.8.0.jar!/clojure/core.clj (io.clj:61)
so, question is: how can I extract that stuff so I can work with it like a collection of files?
by unzipping the jar (it’s a zip file) or iterating resources instead of files
you can do everything you want on resources, you just can’t tell the jvm they are files, because they aren’t
FileSystem is an abstraction and you could create one that worked directly on a zip/jar file as if it were files (like the demo at https://docs.oracle.com/javase/7/docs/technotes/guides/io/fsp/zipfilesystemprovider.html). Not sure that helps you here though… :)
ha, fair enough
I mean, instead of using file-seq get an iterator on the resources
@devn - this should be a decent start
user=> (.getResources (.getContextClassLoader (Thread/currentThread)) "clojure")
#object[sun.misc.CompoundEnumeration 0x77c12409 "sun.misc.CompoundEnumeration@77c12409"]
user=> (def es (enumeration-seq *1))
#'user/es
user=> (count es)
22
user=> (first es)
#object[java.net.URL 0x6be8723d "jar:file:/Users/justin/.m2/repository/org/clojure/tools.logging/0.3.1/tools.logging-0.3.1.jar!/clojure"]
this is based on some quick googling about java, plus looking at the source for http://clojure.java.io/resource
@noisesmith much obliged. i've been using clojure for a good long while and never have used enumeration-seq
unfortunately there looks to be no way to do what i actually want to do, however, which is iterate over the files found in the directory named "clojure" without knowing their names
so i suspect ill need to find the jarfile on disk, unzip it to a temp dir, and read from there
hmm… I know there’s a way to do it. I’ll check if I can make a simple example.
@noisesmith I was just peeking at https://docs.oracle.com/javase/7/docs/api/java/net/JarURLConnection.html#getManifest() but no dice so far
@devn I decided I need to know how to do this - here’s the result
user=> (ir/zip-seq "/Users/justin/.m2/repository/org/clojure/tools.logging/0.3.1/tools.logging-0.3.1.jar")
(#object[java.util.zip.ZipEntry 0x78ffe63f "META-INF/"] #object[java.util.zip.ZipEntry 0x49f430fe "META-INF/MANIFEST.MF"] #object[java.util.zip.ZipEntry 0x5c01b068 "clojure/"] #object[java.util.zip.ZipEntry 0x1b63e89b "clojure/tools/"] #object[java.util.zip.ZipEntry 0x1c2a3bd6 "clojure/tools/logging/"] #object[java.util.zip.ZipEntry 0x74b19b6d "clojure/tools/logging.clj"] #object[java.util.zip.ZipEntry 0x25e2e763 "clojure/tools/logging/impl.clj"] #object[java.util.zip.ZipEntry 0x21c1e474 "META-INF/maven/"] #object[java.util.zip.ZipEntry 0x6cf88f11 "META-INF/maven/org.clojure/"] #object[java.util.zip.ZipEntry 0x146a1b10 "META-INF/maven/org.clojure/tools.logging/"] #object[java.util.zip.ZipEntry 0x26012f01 "META-INF/maven/org.clojure/tools.logging/pom.xml"] #object[java.util.zip.ZipEntry 0x84d8df1 "META-INF/maven/org.clojure/tools.logging/pom.properties"])
@devn code :
(ns org.noisesmith.iterate-resources
(:import (java.util.zip ZipFile)))
(defn zip-seq
[file]
(let [zip (ZipFile. file)
entries (enumeration-seq (.entries zip))]
(mapv #(.getInputStream zip %) entries)))
@noisesmith i was trying to get clever by resolving the jarfile through the resource and opening it with openStream, then using ZipInputStream to getNextEntry, but that failed 😞
I just changed it to return input-streams… but really the best might be a hash-map from entry name to function that returns input stream(?)
are you trying to use ~ ?
no, i was still trying to grab the path to the jar via the resource and there must be something off with that path
@devn this was fun to play with from first principles, but this might just do what you want https://stackoverflow.com/a/5419767 - it’s better than my example above in a few ways
that link is to a specific answer
Using schema, is it possible to validate against 2 keys, that one of those keys is valid? For example validate that password-confirm is the same as password, and if they're not, error password-confirm.
if you mean plumatic/schema yeah I typically use schema/conditional for that - or more specifically constrained eg. (s/constrained {:pw String :pw-c String} #(= (:pw %) (:pw-c %)))
that way if the keys are missing, you get a simple error - also, if you use a named function the error will show the name of the function if the function is what fails
@noisesmith but where does the error message end up in the resulting map? The locations are being used programmatically to communicate error messages. So I would want to result to be: {:pw-c (not (…))}
@dominicm I like how it does it
user=> (require '[schema.core :as s])
nil
user=> (defn a=b [x] (= (:a x) (:b x)))
#'user/a=b
user=> (def a=b-schema (s/constrained {:a Number :b Number} a=b))
#'user/a=b-schema
user=> (s/check a=b-schema {:a 1 :b 1})
nil
user=> (s/check a=b-schema {:a 1 :b 0})
(not (user/a=b {:a 1, :b 0}))
user=> (s/check a=b-schema {:a 1})
{:b missing-required-key}
user=> (s/check a=b-schema {})
{:a missing-required-key, :b missing-required-key}
(not (user/a=b {:a 1, :b 0}))
is as direct as it can get - since the arg was an arbitrary function
and without an arbitrary function I don’t know how to check two keys at once
@noisesmith Yeah, I explicitly need it to be under :b
unfortunately, just due to a downstream consumer.
a custom reify of the apropriate schema protocol just to generate the message / return value it wants?
Hi ! I'm starting a bunch of futures and I'd like to block the main thread until all of them are finished. Is there a way to do that cleanly ?
or something that checks :b explicitly, using the value under :a as a second input?
@florinbraghis (doseq [f futures] @f) will do that
(and return nil once all have returned)
I started poking around the protocol, but I couldn't see how to do it unfortunately. Maybe I need to look at that more closely.
@dominicm what about something like (let [to-check m] (s/check {:b (s/pred (fn [b] (= b (:a m))))} m))
the error message isn’t as nice, but it shows up under the b key
I could hack it with a dynamic var or something 😂 Which is not a style I'm usually keen on.
I suppose with a custom schema on the parent, the dynamic var becomes far more isolated.
what's the best way to select a couple values from a sorted-map in the order that they're stored in the map? (i.e. (unknown-fn (sorted-map :1 "1" :2 "2" :3 "3") [:2 :1]) ==> ["1" "2"])
)
@tanzoniteblack as an aside, the reader in clj lets you create the keyword :1
but it’s evil and the docs say it isn’t valid and some readers reject it
you are allowed to use 1
as a key
good to know. Those aren't my real keys or values, just something I could use as an example to help people see the ordering
@tanzoniteblack wouldn’t select-keys do that?
select-keys uses ret {}
to put it's values into, so I don't think it keeps the order of a sorted map?
oh, right
(fn [m ks] (into (empty m) (select-keys m ks))
- I’ll leave the fancy name up to you
I don’t know of a better option
((fn [m ks] (into (empty m) (select-keys m ks))) (sorted-map 3 "3" 1 "1" 2 "2") [1 3])
returns {1 "1", 3 "3"}
, which 1.) still includes the keys (easy fix) and 2.) isn't in the same order as the original sorted-mapexcept maybe rewriting select-keys to use (empty map)
wait, that sorted map literal is not the same order as the sorted-map
actually no, that's fine
maybe you want something different, like an insertion ordered map
sorted-map doesn't work like I thought it did 😄
haha - there’s a lib with an insertion-sorted map out there
eh...this is small enough, I'm just going to use a vector and iterate over values
(current size of vector: 2, expected size ~5)
performance isn't really an issue on that size
also if you use the insertion-ordered one, you can just iterate and filter for the keys you care about since seq would return them in order
thanks for the input, @noisesmith
by print do you mean print-method (what pr uses) or toString (what str and print use)
print-method is a multimethod that decides how pr / prn show things - this is used for return values in the repl and is meant to be readable by the reader if possible
this can be extended at any time (like any multimethod)
toString is a method on object that is used for str and print / println, and it isn’t meant to be clojure readable, and needs to be defined when defining your class as a method on Object
IIRC while defrecord does give you a nice toString you can override it…
(ins)user=> (defrecord Foo [] Object (toString [this] "hello"))
user.Foo
(ins)user=> (Foo.)
#user.Foo{}
(ins)user=> (str (Foo.))
"hello"
oh - well you can’t change arrays but I guess you could make a thing that acts like one with new toString - I think you might need a more powerful tool than deftype for that since deftype can’t do concrete inheretance
so you’d likely need proxy, or gen-class, or some java code
Then, I define print/equality on the deftype ... okay, so technically I'm not overwriting int-array float-array
but you can’t make other people think it’s an array, is the problem
right - if you dont’ need to fool a consumer about the type, then that should work OK I think
the trick might be methods on array you can’t extend
or things like aget / aset etc. which… dunno how you would make those work without extending the class itself
I'm writing an interpreter, like poor-man's matlab/numpy. These "virtual rrays" can only be accessed by interfaces I define.
oh neverm ind you should be fine then