This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-09-19
Channels
- # 100-days-of-code (12)
- # beginners (116)
- # calva (2)
- # cider (16)
- # cljdoc (5)
- # cljs-dev (26)
- # clojure (161)
- # clojure-italy (7)
- # clojure-nl (9)
- # clojure-spec (49)
- # clojure-uk (112)
- # clojurescript (50)
- # clojutre (4)
- # core-async (2)
- # cursive (4)
- # datomic (192)
- # emacs (10)
- # events (4)
- # figwheel-main (147)
- # fulcro (94)
- # graphql (5)
- # instaparse (1)
- # jobs-rus (1)
- # keechma (10)
- # leiningen (223)
- # luminus (3)
- # mount (23)
- # nrepl (8)
- # off-topic (44)
- # onyx (10)
- # pedestal (5)
- # re-frame (19)
- # reitit (8)
- # shadow-cljs (62)
- # uncomplicate (3)
ahh, I mean in this context I really could do this with just making it a function call
I don't really know why I'm attached to the de-refing syntax. I guess it's just consistent with the other re-frame subscription stuff
@idiomancy You could always reify IDerefable (or whatever the equivalent is in cljs) and implement deref as calling your function 🙂
@seancorfield exactly https://clojurians.slack.com/archives/C03S1L9DN/p1537325353000100
That's what ya get for asking cljs questions in the #clojure channel I guess :rolling_on_the_floor_laughing:
Anyone know how this is even possible? if-let
is continuing to evaluate even though the result is null
. I can repro the error in Clojure 1.9
and 1.10.0-alpha8
.
Not to mention how confusing this has been to debug since the exception is ArityException
. I assume there is no valid arity for nil
functions and it’s also referencing the wrong function name. :man-facepalming:
trying to invoke nil should throw IllegalArgumentException, not ArityException. I’m wondering if what you’re seeing is not actually what’s happening due to locals clearing
if you look at the detailMessage on the right pane, I think that’s where the real ArityException is being thrown - inside an anonymous function, inside kidlink-server.specs.datomic$fn__2484$fn__2485
it would be interesting to open the stackTrace on the right pane there - might not be the same as what you’re seeing on the left
There used to be an Android REPL. Is there still such a thing?
I have one running on my phone made by Daniel Solano Gómez. I can't remember when I downloaded it and can't say why it is no longer on Google Play #useless
the app is useful. I'm useless
@alexmiller: The stacktrace on the right pane was the same as the left and pointed to the same lines of code. You were correct though that the error was in my spec file. I just replaced anonymous functions until I found it. Thanks for your help debugging my issue! 🙂
We just found some exciting non-determinism. Haven't tracked it all down yet, but we can reproduce it.
i=0; while clj -Sdeps '{:deps {org.clojure/clojure {:mvn/version "1.10.0-alpha8"}}}' -e "(let [^Object e (java.util.concurrent.Executors/newSingleThreadExecutor), v (.get (.submit e #(vector :ok)))] (prn $i v) (.shutdown e) (assert (= [:ok] v)))"; do i=$(( i + 1 )); done
That's a little bash loop starting up a new JVM per iteration. I've seen it succeed as many as 17 times in a row, but it usually has failed sooner than that.
I can’t take credit for finding this, is this intentional?
user=> (defn foo [& {:keys [x y z] :or {x 1} :as params}]
#_=> (println "x = " x)
#_=> (println "params = " params))
#'user/foo
user=> (foo :y 2 :z 3)
x = 1
params = {:y 2, :z 3}
the :or
doesn’t apply to the :as
this is the expected result. :as is always the original passed values (here represented as a map)
:or is about making local bindings
that’s about what I figured, but it surprised me (and others)
If the compiler knows the type of e
at compile time, you get an error because it can't resolve .submit
. The problem is that when the compiler doesn't know the type of e
(because we "unhinted" it with ^Object
), it defers method resolution to runtime, at which point it picks one of the .submit
methods in an apparently non-deterministic way. Sometimes it picks the ^Callable which will return a value. Sometimes it picks ^Runnable which returns nil.
FWIW I have run into this very sharp edge before in production with a third party object that implemented both Callable and Runnable, but with different (!) behaviors.
I haven't looked at the reflection code t see where the indeterminism is coming from.
Dunno if it's related to JVM version or not. We did test in one environment that had hundreds of successes before we gave up. I believe that was openjdk version "1.8.0_181" as well.
For a given run of the JVM, it seems to keep picking the same one. Haven't tracked down exactly how it picks, why it sometimes picks the same one, or what has to be done again to have it pick another.
@alexmiller BTW, thanks for clj
-- made testing this a snap
there is nondeterminism in the reflector’s choice of matching method if there are multiple possible matches
to remove nondeterminism, don’t use reflection
Right. But the default behavior is silent non-determinism. This seems bad to me. Has the possibility of having the default be deterministic (such as a runtime error similar to the compiler-time error) been discussed somewhere?
possibly, but I couldn’t point you to it
I agree that a deterministic answer would be better (whether it failed or succeeded)
you could for example build a string of the type names in the params and sort by that, or something like that
I’m actually in the process of looking at some of this stuff anyways in the context of CLJ-2066 (as this can also result in accidentally calling module-private methods rather than public interface methods)
@alexmiller Ok. I found CLJ-792 as well -- after a quick read of the patch, it's not obvious to me if this would solve the problem, and I haven't gotten the patch to apply and pass Clojure regression tests yet. I wonder if that patch is just too ambitious to ever really have a chance of being included.
oh yeah, that’s an oldie
I remember when this was last worked on and I did review it a bit. Conceptually, I think it’s a good idea as this logic is tricky and at least partially duplicated.
it’s likely work on CLJ-2066 will break this patch again even if you got it working
@alexmiller Ok, I won't attempt it then.
i=0; while clojure -Sdeps '{:deps {org.clojure/clojure {:mvn/version "1.10.0-alpha8"}}}' -e '(require (quote clojure.pprint))' -e "(let [^Class fc (class #())] (clojure.pprint/pprint (vec (filter #(zero? (.getParameterCount %)) (.getMethods fc)))))"; do echo '---'; i=$(( i + 1 )); done
@chouser @alexmiller Class::getMethods is non-deterministicwell it might be even non-deterministic within the same JVM -- there's a SoftReference cache under the covers
anyone have any advice on how to do an update-in-where
? maybe where an element in the vec
is a pred
to find the next thing instead of a key or integer?
just gonna keep-indexed
for now.
Anyone knows any open source web-based system in Clojure? I need some inspiration
It's been a while, but I remember CircleCI had their web app open on Github and it was something of a model for others to follow. Not sure what the current state of things is there though.
anybody got a nice way of sorting a sequence of maps by the value of a key in each map?
i should say, the order is specific and predetermined by the value of that key in each map
Is the value of that key in each map a type like an integer, floating point, or string that Clojure's compare
function sorts the way you like?
If so, as hiredman suggested, (sort-by :key-to-sort-on my-sequence)
should do it.
If the values associated with that key need additional custom logic for sorting in your desired order, then you may want to write a custom comparator function, too, and/or use a function to transform the value to something else that compare
already sorts the way you like.
and a sequence of maps to sort according to that list of values, by a fixed key that exists in each map
user=> (def m {:w 1 :y 2})
#'user/m
user=> (sort-by (comp m :k) [{:k :y} {:k :w}])
({:k :w} {:k :y})
user=>
You can create a map like this: (def sort-rank {"b" 1, "c" 2, "f" 3})
.
Then if your sequence of maps has a key :my-sort-key
, and the value associated with that key is one of "b" "c" or "f", then you can use (sort-by #(sort-rank (:my-sort-key %)) my-sequence)
The first arg to sort-by
there is a little function that first gets the value associated with the key :my-sort-key
, and then it looks up that value in the map sort-rank
, getting one of the number 1, 2, or 3 in my example def above, and then the elements of your sequence will be sorted via Clojure's compare
function on those values 1, 2, or 3
which will be from smallest to largest
sort-rank
need not be specified as a map -- I gave it that way in the example because it makes determining the sort rank a quick operation for each element in your sequence (i.e. nearly constant time, vs. a linear time scan through a list or vector)
And if I'd actually looked at what hiredman wrote, I would have noticed I was being redundant 🙂 My #(sort-rank (:my-sort-key %))
is equivalent to his shorter (comp sort-rank :my-sort-key)
sort
and sort-by
are 'stable' for any two elements that have the same comparison key. That might not be the case you are seeing, though. It shouldn't depend upon the lengths of sort-rank and my-sequence.
If you can boil it down to a small example you can share, someone could take a look at it to see if they can understand what is going on, but I understand if boiling it down to a small example can be too time-consuming.
I'd like to use https://github.com/oliyh/lacinia-gen to do generative testing of an app that consumes a GraphQL (Lacinia) API. However, I'm trying to figure out how I could further constrain the values so that I can test specific use cases
Hey, so... what does cljc stand for? Clojure Core? Clojure Code? Clojure Conditional?
clojure conditional https://github.com/clojure/clojurescript/wiki/Using-cljc
I would have thought it stood for 'common' as in code that is common to clojure and clojurescript.
according to Rich, who I will consider the authoritative source :)
I have a somehow stupid question: I wonder why many clojure functions are not designed in a way to have a "mappable parameter" in the end: (str/split "Clojure is awesome!" #" ")
So in this case, the str/split last parameter in my view should not be the separator, but the string that should be separated,
(doc clojure.string) actually describes the rationale
str/join is an exception (and I think str/split could have used a similar rationale) to put the partial-able arg first
I don’t know but suspect it’s not there b/c of the optional limit arg which gets a little weird
@alexmiller Glad you see it also as an exception. I somehow managed to use lots of functions like this example.
then it will not send the data to the last position but to the position where the operator applies.
this is close to what as->
does, but as->
is simpler
I am not coming any further with the docs on as-> operator. So say I build a pipeline with -> and then I have some functions where I need to "fill in" a parameter that is not the last one...
Exactly, (-> x (foo) (as-> $ (bar $ $)) (baz))
Thread macros do pure syntactic rearrangement. In the case of an anonymous function that means putting the result of the prior into the list defining the anonymous function. If you macroexpand the form, you’ll see why this won’t work
if threading form is not that tall, I go with as-> from the beginning:
(as-> x $
(foo $)
(bar $ $)
(baz $))
is there any reason it is worse than your example? @noisesmith@U051HUZLD that's a subjective decision, to my eye using the placeholder in every clause introduces a lot of unneeded clutter
as-> was designed to be usable inside ->
I payed around with a few examples, and I also find it easier to use as-> as a replacement of -> or ->> really. So in cases that the functions that I want to call have different patterns, then using as-> as a sort of more general form seems to work fine
I've wondered about this for a while too; when I first came to Clojure, I was coming from Haskell and I was currying my functions and composing function transformations on data by .. well, directly using comp (so as an example, ((comp (add 1) (sub 2) (mult 3)) 12)
instead of (-> 12 (+ 1) (- 2) (* 3))
, where add, sub, and mult are assumed to be curried). Then I discovered ->
and ->>
, but also discovered that some things seemed to be fit for the comp
/ ->>
way, and others for the -> way, so I've wondered about that myself (the example being drop
is (drop n coll)
and composes with other functions with ->>
, but split
is (split string delimiter)
, and composes with ->
.)
->> can be used inside ->, in fact all the "arrow macros" can be used inside ->
the thing to be careful of is that these macros are not semantic operations, they are a way of folding and unwrapping source forms eg. this next example is not an analog to currying or method chaining:
user=> (->> (+ a b) (let [a 31 b 11]))
42
The point is that ->> rewrites code before compiling, that's all it does
I get that. This is what a macro does, and it makes sense, because otherwise the whole code would not be valid clojure syntax.
no - macros don't evaluate any of their arguments, and thus can control how they get evaluated arbitrarily.
in the case of ->>
, it takes the arguments (+ a b)
and (let [a 31 b 11])
, then - at compile time - rewrites them into (let [a 31 b 11] (+ a b))
which is then what eventually gets evaluated
(defn get-data [mySymbol] (->> (slurp (str "resources/CSV/" mySymbol ".csv")) (csv/read-csv) (drop 1) ; drop header row (map parse-row-)))
Only after ->>
has finished, and the new expression has been created, is anything evaluated. Until then it goes from (+ a b)
unevaluated, to (let [a 31 b 11] (+ a b))
unevaluated, and so on.
And first it slurps, then it processes csv , then it drops headers, then it parses the row data.
@UCSJVFV35 i suggest you read the following: https://www.braveclojure.com/read-and-eval/ https://aphyr.com/posts/305-clojure-from-the-ground-up-macros
thanks @U61HA86AG
I would add that if your goal is to write code that is clear to others, I would not hold up (->> (+ a b) (let [a 31 b 11]))
as a shining example of clarity to humans.
I would almost go so far as to say that someone writing code like that might be trying to pull a fast one on you.
the rule(s) are explained in the FAQ: https://clojure.org/guides/faq#seqs_vs_colls https://clojure.org/guides/faq#arg_order
if threading form is not that tall, I go with as-> from the beginning:
(as-> x $
(foo $)
(bar $ $)
(baz $))
is there any reason it is worse than your example? @noisesmith