This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-09-01
Channels
- # announcements (10)
- # aws (1)
- # babashka (19)
- # beginners (104)
- # calva (50)
- # cider (17)
- # cljs-dev (135)
- # cljsrn (56)
- # clojure (240)
- # clojure-dev (4)
- # clojure-europe (19)
- # clojure-nl (2)
- # clojure-uk (7)
- # clojurescript (22)
- # conjure (2)
- # css (1)
- # cursive (10)
- # data-science (1)
- # datomic (60)
- # emacs (2)
- # events (2)
- # exercism (1)
- # figwheel-main (3)
- # fulcro (13)
- # graalvm (5)
- # gratitude (1)
- # inf-clojure (4)
- # introduce-yourself (5)
- # jobs-discuss (21)
- # lsp (36)
- # malli (6)
- # meander (8)
- # missionary (12)
- # off-topic (14)
- # pathom (13)
- # pedestal (10)
- # polylith (42)
- # re-frame (5)
- # reagent (12)
- # reitit (3)
- # releases (8)
- # sci (10)
- # shadow-cljs (37)
- # sql (5)
- # tools-deps (6)
Has anyone created a tool that reads Clojure/JVM stack traces as printed in text form, without any pretty-printer/formatter involved, and then shows them in one of several possible pretty-printed forms?
Kinda There's some code on Chlorine that does that
But it converts a Java Throwable into a reagent "react component": https://gitlab.com/clj-editors/repl-tooling/-/blob/master/src/repl_tooling/editor_integration/renderer.cljs#L426-462
I would guess that if a plain old text printed stack trace can be read in a way that produces a stack trace JVM object, you could use any of the existing stack trace pretty-printers on it, yes? So maybe my question is: is there a way to read a plain old text printed stack trace and produce a stack trace object in memory?
There are exceptions, and from exceptions you can get an array of stacktrace elements, which are trivial to construct
But exceptions are an open set, so could have all different kinds of behaviors (private constructors, ignore the set stacktrace method, etc)
https://docs.oracle.com/javase/7/docs/api/java/lang/StackTraceElement.html#StackTraceElement(java.lang.String,%20java.lang.String,%20java.lang.String,%20int) huh didn't know that about -2
Ok, I’m sure I’m doing something really stupid, but I can’t see it in my addled state:
(binding [*compile-path* "/Users/colin/dev/cursive/out/production/cursive"]
(compile 'cursive.intellij.class))
=> cursive.intellij.class
And then…
~/d/cursive (deprecations)> ls /Users/colin/dev/cursive/out/production/cursive/cursive/intellij/
~/d/cursive (deprecations)>
Any ideas why I’m not getting any classes generated?@cfleming is the ns already loaded? IIRC it only works for namespaces not yet loaded
is there a good idiom for conditional doto
?
(doto (DecimalFormatSymbols.)
(.setDecimalSeparator decimal)
(.setGroupingSeparator grouping))
handling when decimal
or grouping
might be nil and omit that expression (statement?)Only one I’ve seen is this: https://github.com/ptaoussanis/encore/blob/07a6ef576eb23912d4d02f4ac5641a2b351e6dc5/src/taoensso/encore.cljc#L381-L391
@U07S8JGF7 i saw that one with apropos but was hoping there was a clever combination of things from core. @U0CL38MU1 yeah i ended up doing the obvious let when, when, return object just wondering if there was a better idiom. Apparently there isn't and i agree this would be nice to have
Fogus had some clever <<
macro at one point, and I’m wondering if it would cover this case.
would double doto
work?
(cond-> x
y (doto (doto z))
...)
Can't be bothered to thoroughly check... excuse the noise if it doesn't(let [a "1"
b "2"
c nil]
(str
(doto (StringBuffer.)
(cond-> a (.append ^String a))
(cond-> b (.append ^String b))
(cond-> c (.append ^String c)))))
(let [a "1"
b "2"
c nil]
(str
(doto (StringBuffer.)
(cond-> a (.append ^String a))
(cond-> true prn)
(cond-> b (.append ^String b))
(cond-> c (.append ^String c)))))
doto
always passes the same thing through to the next expression, regardless of what each expression returns
I don't knw if this is is relevant, but there is let?
and also the lib swiss arrows
https://github.com/egamble/let-else
https://github.com/rplevy/swiss-arrows
seems like interesting stuff in there but i don't think i'd want to take a dependency on that
Now this is gonna bother me. Does anybody know where that <<
(or maybe <<-
) macro that was going around about a year ago went?
😲 do you have an example of how you would use it? Don’t really understand the one in the tweet
There’s also the classic https://github.com/randomcorp/thread-first-thread-last-backwards-question-mark-as-arrow-cond-arrow-bang :)
that library is so much fun. not useless per se, but certainly not anything i want touching one of my codebases, and yet i love reading through the code and marveling at it
Coming from scala, I really want to use it. The nil-shortcutting diamond thingy is just so good.
Well, I find the threading macros frustrating, because collection functions need to use ->>
but hashmap functions use ->
. The wand thingie is basically as->
but better. And nil shortcutting is pretty cool in an api environment, where inputs can be bad.
Also the side effect arrows are nice. Being able to add (-!> println)
and go about your debugging is nice.
(-> something
(doto (println)))
@U02DEQJ409F the rationale for the two types of arrows is that there are "sequence operations" (what you called collection functions) which take the sequence as the last argument. They are for stream processing basically. And there are collection operations (which the map functions are, along with nth, and a bunch of other similar things), and those take the collection first. Basically if you're trying to transform a stream, you need ->>, but if you're trying to work with an individual piece of data, then you need ->. Also you can combine -> with as-> to make some nice chains even when the first argument isn't what's needed.
the threading macros also work together
(-> {:things (range 10)}
:things
(->> (map inc) (reduce +))
(as-> x (* 2 (/ x 11))))
... as Joshua said 😉Wow. Coming here was my best decision today. Thanks for that information. This is literally gonna change my life x)
https://stuartsierra.com/2018/07/06/threading-with-style was a nice read about the subject as well
https://github.com/Reactive-Extensions was one of the delightful things I found in other languages. Threads have the same spirit, and I find them cleaner/more elegant
I've started to use transducers a lot more where I had previously used ->>
which seem to overlap with the reactive extensions ideas from other langs
I'd use transducers more if they were more ergonomic.
(sequence (comp (map inc)
(filter even?))
(range 10))
I find that much more awkward to write, and more importantly harder to read, than a ->>
pipeline of normal sequence functions:
(->> (range 10)
(map inc)
(filter even?))
And other developers less familiar with transducers will find the difference in readability even more stark. So even though transducers are better for performance and conceptually cleaner, I can't justify defaulting to them(of course you can use into
instead of sequence
, but that doesn't change much)
well ... sequence
is lazy and into
isn't ... I think that making lazyness optional at the point of application is a great feature of transducers.
I was going to ask : I have to map over a sequence and also sort it. Would a transducer to that in one pass ?
well a lazy-seq won't run through the whole dataset in one go, and you need to realise all the data in order to sort it (cos the last element might be the first one 😉 ) ... but
(transduce (map dec) (completing conj sort) [] (range 10 0 -1))
that will process the sequence, and sort the data at the end, and using the xforms lib you can write this
(require '[net.cgrand.xforms :as x])
(into [] (comp (map dec) (x/sort)) (range 10 0 -1))
which might read a bit nicer and will let you sort the data in the middle if you want 😉 ...
but the transducer version won't create an intermediate lazy seq for each stepCreating a sorted collection will not be particularly efficient whether you use transducers or not. Probably the best way to do it would be to use into
with a sorted-set-by
as the target and then call seq
on the result.
Although cgrand.xforms may be more efficient since it uses java's arraylist sort without sorting the intermediate steps
into
a sorted set will remove duplicates which probably isn't what you want. I would have thought that the xforms sort would be most efficient, but test it with your dataset ...
What options are there for implementing a swagger/openapi-v3 server in clojure these days? When I last looked reitit seemed to be one of the best bets; though it still looks like it doesn’t yet support openapi v3. Has the situation on what viable options there are changed at all?
To my knowledge the situation for reitit hasn’t changed. I’m asking whether there are other options now? (Rephrased question to be clearer).
ahh thanks — I was trying to recall the name of that one — sadly doesn’t look finished nor updated recently 😕
just discussed last week about adding OpenAPI3 finally to reitit. There have been many people contributing to that, but not completely done. Just work.
I am performing a read
on some clojure and it the metadata is lost during the read (or so it seems) ... I guess I'm missing something simple so would appreciate some guidance
(read-string "(deftype StringReader
[^String s ^long s-len ^:unsynchronized-mutable ^long s-pos]
Reader
(read-char [reader]
(when (> s-len s-pos)
(let [r (nth s s-pos)]
(update! s-pos inc)
r)))
(peek-char [reader]
(when (> s-len s-pos)
(nth s s-pos))))")
=>
(deftype
StringReader
[s s-len s-pos]
Reader
(read-char [reader] (when (> s-len s-pos) (let [r (nth s s-pos)] (update! s-pos inc) r)))
(peek-char [reader] (when (> s-len s-pos) (nth s s-pos))))
it says that s-pos
cannot be changed but ^:unsynchronized-mutable
is set there to counter that
it's pretty easy to check if the metadata is still there, just navigate to the symbol and call meta
on it
(deftype StringReader [^String s ^long s-len ^{:tag long, :unsynchronized-mutable true} s-pos] Reader (read-char [reader] (when (> s-len s-pos) (let [r (nth s s-pos)] (update! s-pos inc) r))) (peek-char [reader] (when (> s-len s-pos) (nth s s-pos))))
thank you for the wisdom @borkdude... I just meant is there a *retain-meta*
type thing on read
are you evaluating this in the right namespace context? are you sure update!
resolves to that macro?
so as @hiredman suggested ... the metadata was still there but I wasn't sending it effectively
FYI I was evaluating the whole ns
so that was always going to work but without context it was a good suggestion
Is there a way on argue that it's better to not have nil values in a map when you're parsing some data?
right now I've made a function that parses CSV's
(parse-csv
(str "column-1,column-2,column-3\n"
"row1-a,row1-b,row1-c\n"
"row2-a,,row2-c\n\n\n"))
=>
[{:column-1 "row1-a", :column-2 "row1-b", :column-3 "row1-c"}
{:column-1 "row2-a", :column-2 "", :column-3 "row2-c"}
{:column-1 ""}
{:column-1 ""}]
instead of having blank strings or nil's when the blank strings came
I think that a better default would be like
(parse-csv
(str "column-1,column-2,column-3\n"
"row1-a,row1-b,row1-c\n"
"row2-a,,row2-c\n\n\n"))
=>
[{:column-1 "row1-a"
:column-2 "row1-b"
:column-3 "row1-c"}
{:column-1 "row2-a"
:column-3 "row2-c"}]
IIRC Rich has expressed a preference for omitting keys, and I think that's reflected in the design of at least clojure.spec
some people is saying that I'm missing some information when I do that
for me as myself I don't think so
some argument about it on clojure would be
(->> [{:a 1} {:a 1 :b 2}]
(map (fn [{:keys [a b] :or {b 0}}]
{:a (inc a)
:b (inc b)})))
(->> [{:a 1 :b nil} {:a 1 :b 2}]
(map (fn [{:keys [a b] :or {b 0}}]
{:a (inc a)
:b (inc b)})))
Error printing return value (NullPointerException) at clojure.lang.Numbers/ops (Numbers.java:1068).
Cannot invoke "Object.getClass()" because "x" is null
the fn in map would be the one that does the parse
instead of validating stuff only
Yeah :or
doesn’t work like most idomatic clojure. (On the same premise that I said before.)
didn't got what you mean by that
"doesn’t work like most idomatic clojure."
I don't think this is idiomatic
:thinking_face:
and :or
does a contains?
check because there’s a difference between “I have this value and it’s nil
” and “I don’t have this value”
then why not have only data that does not have nils?
if or could check it?
using :or only makes sense when there's a sensible default value which the user always wants when calling that code, and where it's invalid to not have that data. It should not be used to provide default data for when there is missing information.
then it should be better to have empty strings? not nil?
,,
in a CSV means either: I don’t have this data or I have this data and the value is nil.
Given the semantics of CSV it’s better to assume the latter and move on.
(I know from experience that using ""
leads to problems. For CSVs, I usually trim all whitespace and then translate ""
to nil
.)
why then you would have keywords with nil values?
To say that you know what value is for that keyword, and the correct value is nil
Which is distinct from not knowing what the value for that keyword is.
hey everyone, i am a beginner
(defn func
([] sentence)
([name] (str sentence name)))
(func "harshit")
is this code wrong ?
there's a #beginners channel with lots of people who will take the time to work through it with you
On the CSV parser, I think it's valid to have nil values in the map, specifically because it's parsing tabular data. In this format there is no distinction between "we have this data and it's null" and "we don't have this data" so it's better to preserve the semantics of the original format, which is that every row has every field, and some may be nil. In general though, if you don't have information for a particular field of some domain object, just don't include the key. This gives you strictly more information than always storing it with nil does. If you always have nil values for specific keys then you're effectively emulating place-oriented-programming with maps.
then why not have only data that does not have nils?
if or could check it?
one reason we need to be able to have nil under a key: removing a key from a record can change its type to hash map, setting the value to nil does not do this
(ins)org.noisesmith.art.audio=> (defrecord Foo [a b])
org.noisesmith.art.audio.Foo
(ins)org.noisesmith.art.audio=> (type (dissoc (->Foo 1 2) :a))
clojure.lang.PersistentArrayMap
(ins)org.noisesmith.art.audio=> (type (assoc (->Foo 1 2) :a nil))
org.noisesmith.art.audio.Foo
also, more generally, it is possible to put a nil into any place an Object is expected in the jvm, it would be awkward to create an exception to this
@d.ian.b is your question "why is it possible" or "why would you leave data in this state"?
=> why would you leave data in this state if you could not have nil? this one
a helper function like this is relatively common
(ins)org.noisesmith.art.audio=> (defn canonify [m] (into {} (remove (comp nil? val)) m))
#'org.noisesmith.art.audio/canonify
(ins)org.noisesmith.art.audio=> (canonify {:a nil :b 1 :c nil :d 2})
{:b 1, :d 2}
(though probably with a different name)
these days, I typically put the effort into avoiding putting the nil in in the first place
much like the "bag of relevant attributes" approach taken in spec, datomic, etc (and inspired by similar approach in RDF), I think this is usually the best default approach in Clojure. it's not always the best - sometimes it helps to have "regular" rectangular maps (and CSV and database tables are places where this can come up) so warrants some intentional thought up front
One idiom I’ve started recently using is using (or …) after destructuring instead of the destructure :or
(let [{:keys [a b c]} {:a 1 :b 2 :c nil}
c (or c 42)]
c)
;=> 42this is exactly the purpose of :or
in destructuring
(let [{:keys [a b c] :or {c 42}} {:a 1 :b 2 :c nil}]
c)
Re: database and nil
-- next.jdbc
has a next.jdbc.optional
namespace with result set builders that omit nil
-valued keys (as opposed to the regular builders that leave them in) so you have a choice -- precisely for this sort of reason.
You need nil
values in hash maps for UPDATE
and sometimes for INSERT
but it can be a lot cleaner to avoid them for SELECT
operations.
@noisesmith good point, yes
@alexmiller reminds me the Maybe Not talk > We do not, in Clojure, tend to do this using nulls, right? We do not put a key in our map, and put nil in as the value there. And I am going to talk about the differences there. https://github.com/matthiasn/talk-transcripts/blob/master/Hickey_Rich/MaybeNot.md
@marciol Yes! Semantically, it doesn’t make sense, does it? “I’m setting the value of this thing, and the value is … nothing!”
Definitely… If I’m getting rid of the value under a key, I use (dissoc …) There can be edge cases like in the case of defrecord like pointed out by @noisesmith, but that’s not the typical case.
Is it possible to do this in a library, or has the core team considered adding a way to omit nils in collection literals? E.g.,
[:a :b #omit-nil (function-that-will-return-nil)] => [:a :b]
I would have thought that wouldn't work, because the #omit-nil
bit is a reader tag and the function will need to be run at runtime, after it's been read and compiled ... Right?
You are probably right, I have a gap in my knowledge, never looked into reader literals at all
@isak That sounds like mixing compile-time and runtime concerns?
(let [x (function-that-will-return-nil)] (cond-> [:a :b] (some? x) (conj x))
@seancorfield Well it could just compile to a different expression, for example conditionally assoc! on a transient map, no?
And yea I've used alternatives like that before, also made some functions like assoc-some
, but it seems more cumbersome than it needs to be
I am not 100% sure either, but that doesn’t sound like it would be even possible. Pls correct me if I’m wrong.
How would the compile-time phase know what (function-that-will-return-nil)
returns in order to clear that :b
key?
It doesn't have to know it, it would compile to an expression that would check before associng. For example:
{:a "A" :b #if-some (function-that-will-return-nil)}
=>
(let [m (volatile! (transient {:a "A"}))]
(when-some [b (function-that-will-return-nil)]
(vswap! m assoc! :b b))
(-> m deref persistent!))
@raspasovAh, got it. Perhaps instead of that weird #if-some syntax, do a macro like:
(without-nils {:a "A" :b (function-that-will-return-nil))})
The without-nils
macro would transform the code:
{:a "A" :b ^:no-nil (fn [x] nil)}
into some variation of your code above:
(let [m (volatile! (transient {:a "A"}))]
(when-some [b (function-that-will-return-nil)]
(vswap! assoc! :b b))
(-> m deref persistent!))
The easier way:
(defn clear-nils
"Remove the keys from m for which the value is nil"
[m]
(apply
dissoc m
(for [[k v] m :when (nil? v)] k)))
Have used that function, once in a blue moon… But again, I try to avoid having the nils there in the first place.
You can walk randomly shaped/deep maps and data-structures and get rid of whatever you want as you walk them.
Yea I have done that approach too, works pretty well, because then you can take it a bit further and remove e.g., vectors that become empty after the steps above
Again, I prefer not having that problem in the first place, if possible. If I control the data/input, I would very much prefer that option 🙂
Yea, I was just proposing this as a more concise way to control it, because every alternative we've discussed is still more verbose
Right… Same rule applies, imo. Clean up the vector in the first place, if you can, or make the code work without caring whether the vector is empty or nil, etc.
I think where it comes up is if you are building something like a query AST, where some of the parts are dynamic. For example in some test code, I have this:
:venia/queries
[[:employees
(if first-n
{:first :$n :after :$cursor :orderBy :$order}
{:last :$n :before :$cursor :orderBy :$order})
(filterv
some?
[page-info
[:edges
[[:node [:dbId :description]]]]])]]
Where page-info
is a binding that may be nilYea it does, it is just pretty verbose compared to this:
:venia/queries
[[:employees
(if first-n
{:first :$n :after :$cursor :orderBy :$order}
{:last :$n :before :$cursor :orderBy :$order})
[#if-some page-info
[:edges
[[:node [:dbId :description]]]]]]]
Especially if it comes up multiple places in the query.Right… I actually might have it like:
[[:employees
(if first-n
{:first :$n :after :$cursor :orderBy :$order}
{:last :$n :before :$cursor :orderBy :$order})
(filterv some?
[page-info
[:edges
[[:node [:dbId :description]]]]])]]
In Cursive, it gets indented like this:
[[:employees
(if first-n
{:first :$n :after :$cursor :orderBy :$order}
{:last :$n :before :$cursor :orderBy :$order})
(filterv some?
[page-info
[:edges
[[:node [:dbId :description]]]]])]]
Another option is to avoid the execution from the top:
(when (and page-info etc-info)
;query
)
Yea, I write a lot of React(Native) view code. That’s why I reduced the indentations 🙂
With deeply nested ASTs, combined with conditionals/filter etc, I like less visual nesting
That was not the default, I believe. It would indent under the {} and everything drifts.