This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-10-09
Channels
- # announcements (5)
- # babashka (1)
- # beginners (116)
- # calva (139)
- # cider (11)
- # clara (2)
- # clj-kondo (13)
- # clojure (247)
- # clojure-dev (18)
- # clojure-europe (5)
- # clojure-france (2)
- # clojure-italy (2)
- # clojure-nl (7)
- # clojure-spec (24)
- # clojure-uk (34)
- # clojurescript (41)
- # cursive (11)
- # data-science (2)
- # datomic (33)
- # emacs (10)
- # events (3)
- # fulcro (134)
- # graphql (9)
- # jackdaw (3)
- # jobs (1)
- # joker (20)
- # kaocha (3)
- # leiningen (7)
- # luminus (2)
- # malli (3)
- # music (1)
- # pedestal (7)
- # re-frame (25)
- # remote-jobs (7)
- # ring (7)
- # shadow-cljs (85)
- # spacemacs (13)
- # testing (2)
- # tools-deps (60)
- # xtdb (11)
- # yada (7)
s/nilable expects a spec
Please help me track down this.
My :dev alias has :jvm-opts ["-XX:-OmitStackTraceInFastThrow" "--illegal-access=deny"]
and I can verify that it is in effect with
ps -ef | grep clojure.main | grep -- -XX:-OmitStackTraceInFastThrow | wc -l
returning 1.
Hi, I noticed a small inconsistency in how the regular clojure reader and the syntax-quote reader treats map literals:
(type {:a 1})
;; => clojure.lang.PersistentArrayMap
(type '{:a 1})
;; => clojure.lang.PersistentArrayMap
(type `{:a 1})
;; => clojure.lang.PersistentHashMap
code that cares about the difference between HashMap and ArrayMap is broken, IMHO
you can use an insertion ordered map type if you need that property, ArrayMap will return a HashMap when you conj if it hits the size limit
Oh, I know it's an implementation detail and I'm not relying on it in any way - just wondering what this means for performance of syntax quoted maps in macro-generated code, because ArrayMaps are more efficient for smaller sizes
macroexpanding shows that syntax-quote always uses hash-map
regardless of the number of elements, which it probably can't know at compile time due to unquote splicing
(macroexpand '`{:a 1})
;; => (clojure.core/apply
;; clojure.core/hash-map
;; (clojure.core/seq
;; (clojure.core/concat (clojure.core/list :a) (clojure.core/list 1))))
Is there such a thing as a hook for automatically indenting Clojure code upon merging (or somewhere in the process of PR reviewing) for github?
Or in a github-unrelated project?
We’re tired of indentation differences filling up PRs in our team, so we’d like to standardize
is there no way to lint on commit in clojure?
i prefer commit-hooks to force linting (with the obvious drawback that it might hinder something thats needs to be done ASAP) since it give people the chance to learn what the set standard is
Have a look at https://tonsky.me/blog/clojurefmt/ Which solves the problem differently, but we've been using it with great effect. Cursive does a few things differently from what I would expect (alignment in let blocks), and otherwise it works
there's also cljfmt - I've used that as a pass/fail hook on PRs
lein cljfmt fix
doesn't do the same kind of thing @dominicm?
@andrea.crotti Cljfmt is very minimalistic. For example it won't "fix" (because I hate this) [a. 10\n long-key. 4]
.
ah right zprint runs a lot faster though since it's using graalvm
https://www.reddit.com/r/Clojure/comments/dff2q6/easy_on_eyes_clojure_intellij_syntax_colors/
@dominicm @andrea.crotti @me1243 @danie cheers. Do you guys know of any work to hook up zprint or cljfmt to some central process, like github PRs?
Or do you have any experience with it directly?
@reefersleep we just have a job in CircleCI to fail the build if lein cljfmt check
fails
What’s your experience with this setup? Does everyone like it, or is it ruled by a majority (or a lead)?
And what does a fail mean - does it mean that you need to run some auto-formatting process on your branch manually and amend your PR?
yeah you just need to run lein cljfmt fix
locally and commit/push
well some people complained in the beginning, but if most people are using Emacs or Cursive, it's quite rare that it fails tbh
as a pre-commit hook maybe lein cljfmt fix
is too slow, but zprint might be fine
Cool! When you introduced this, did you have one commit that did lein cljfmt fix
on all of your existing code, to establish a baseline?
we have stability problems with our PR checks at the moment, so adding another, and just for indentation, would annoy people greatly.
Therefore it’d probably be nice to have as a commit hook as well.
I don't think you need anything zprint specific here. There's probably github hooks or services. Commonly people have a pre commit hook to run it automatically. That runs on people's machines.
anyone using zprint in a pre-commit hook, or basically as a gofmt like formatter for teams?
If you do it at the pr level, then each commit contains reformatting. Makes it harder to review. If you have something that rewrites history then signatures become invalid.
Sounds good, but this requires ensuring that each developer sets it up locally, which might be a hassle, or at least is not certain to be done thoroughly - isn’t a combination of pre-commit hook and PR hook the most safe and least noisy approach?
Pr level to fail ci as @andrea.crotti mentioned.
I don't even need the pre commit hook because unless I do something deliberately weird Emacs clojure-mode does the right thing
so well it depends on your team maybe but I don't think it's such a big deal
they'll get used quickly
Feels very hostile towards users of those editors if you pick based on a "preferred" editor. It elevates one above the others.
Well I think you can't make everyone happy though
If different editors have different defaults
and we have vim /cursive users but I've never heard complains because of cljflmt
A while ago I started work on a Git pre-push hook in Bash and Planck with the idea of allowing everyone in a team to use whatever indentation they like. It’s probably alpha quality at the moment. If there’s interest, I can look into tidying it up and getting it into a state where other people could use it with some confidence. If you think you might find it useful, or if you think it’s wrong-headed, please let me know! Some details: • After pulling, you indent the code as you like. (To make things easy for me, I added an Emacs command to re-indent all Clojure and ClojureScript files in a project and create a whitespace-change commit.) • When you push, a hook rewrites commits to use the canonical indentation. This is done with cljfmt, using options that only change indentation. (This could be made more flexible — it doesn’t have to be cljfmt.) • Any commits that only change indentation are discarded. • After the rewritten commits are pushed, a new local commit is created with your local indentation. • It takes care to keep your untracked files, worktree and staged files as they were. (That was pretty fiddly.) For anyone super-interested, there might be enough information in the README to give it a go. If not, ask me questions. It’s at https://github.com/simon-katz/nomis-git-formatting. It’s been tested (a while ago) with: - lein-cljfmt 0.6.4 - Leiningen 2.9.0 - Git 2.16.1 - Planck 2.19.0 - Clojure 1.10.0 - Bash 3.2.57 (which is really old, but it’s what comes with macOS; maybe I should upgrade) - macOS High Sierra 10.13.6
Whoa that's quite cool
@U06A9U5RP is this intended to make the commonly agreed formatting method invisible to the individual developer while he’s working on his branch?
@reefersleep That’s kind of the idea, but local vs remote rather than branch vs master. Don’t argue about formatting and use whatever suits you, the individual developer. And the git history won’t have whitespace changes. It doesn’t seem that there’s much interest in this, though.
When you say “use whatever suits you individually”, the code that you’re not currently worked on is all formatted according to the automatic process, yes?
I’m trying to visualize how it would be to work with, and I don’t know if just having the indentation that you’ve just touched be suited to your style would be enough of a selling point for most developers. Your general idea is cool though 🙂
Personally, I don’t know why I’d want to be viewing the file(s) I’m working on in a different indentation than I’d see initially on checking out master or viewing the files on github.
I’d just use the agreed convention locally.
And though I haven’t looked thoroughly at your thing, I might be worried that it’d cause more git management hassles than I’m already experiencing 😮
Yeah, git management hassles is certainly something to consider. The idea is that after cloning or pulling, you reformat the whole project to suit you and create a whitespace-change commit. So everything you look at after that has your preferred indentation. This commit disappears when you push.
Aha 🙂
It’s true that you can ignore whitespace, but it’s still noise in the file’s commit history. But that’s a different discussion 🙂
I just learned about zprint and I am mostly curious about it. We use cljfmt but I have the feeling we could go further with zprint
How do you use it?
As a github hook?
For clojure metrics, is there something simpler than a histogram to just store one numerical value at a time?
I just want to do (simple/update! (simple/simple "my-simple-metric-name") 10)
and then be able to get 10
back from it on my metrics endpoint.
With a histogram I seem to then only have access to a min, max or mean, or all the values in the sample.
(let [one-numerical-value (atom 0)]
(prn "Number is " @one-numerical-value)
(swap! one-numerical-value inc)
(prn "Number is now: @one-numerical-value))
I mean, you’re talking about things in the context of statistics, but what you need does not seem statistics-related and is a quite simple request, unless I misunderstand you
or (defonce one-numerical-value (atom 0))
So I want to register a metric with the default metrics registry so that I can get the value out on grafana, it's just bizarre to me that all of these somewhat complicated metrics are built in but there isn't just a store my value
equivalent.
In the end I went with a histogram of 1 value as it produces the correct graph for my dashboard, but it's a bit weird.
¯\(ツ)/¯
I agree, I guess! If you’re bound by the framework, it does seem weird that that’s missing.
I guess I can supply a uniformReservoir of size 1, just seems a bit verbose
(defn simple-hist [title]
(.histogram mc/default-registry
(mc/metric-name title)
(reify MetricRegistry$MetricSupplier
(newMetric [_] (Histogram. (mc/uniform-reservior 1))))))
Went with this for now, seems a bit wrong that I have to use mean to get my single value back. Feel like I'm missing something really obvious here for how to simple put and get a single valueI wonder if it documented somewhere that the Clojure reader accepts code like this:
(defn ❤️ [x]
(str "I ❤️ " x))
(❤️ "Clojure")
The Reader page says: ”Symbols begin with a non-numeric character and can contain alphanumeric characters and *, +, !, -, _, ', ?, <, > and = (other characters may be allowed eventually).” Which doesn't seem to include emojies.@hybas3, that's why I ask. It is not clear to me why the characters are enumerated if other characters can be included. Also ClojureScript does not accept that code.
The specification is intentionally not exhaustive of what characters that the implementation accepts
in other words, it's not documented that this isn't accepted
The specification enumerates characters promised to be good in symbols.
and I would say it's unlikely that your ability to use unicode there would be narrowed later
does this mean that the inability for clojurescript to accept this code is a bug :thinking_face: ? or is this rather a “runtime” decision not a grammatical one ?
I'd say it's a host/dialect decision, so up to ClojureScript whether they want to accept
maybe ClojureScript could add support for this by modifying munge
to turn special unicode characters into something acceptable in javascript variable names
currently (munge "❤️")
returns "❤️"
which doesn’t work as a property name (`obj.❤️` is invalid)
I'll go for it. I love that the code works! I'm trying to help port parcera to cljc
, which is why I ask. https://github.com/carocad/parcera/issues/8
there are a handful of things that I would stay away from in symbols, like |
(as that is a future possible delimited symbol character)
@joe.lane if we were to have a way to specify symbols (and keywords) with spaces and any character in them, we would probably use surrounding | | to delimit those
isn't | used in clojure clr already? https://github.com/clojure/clojure-clr/wiki/Specifying-types
|I'm a valid symbol|
which is not say that we're doing that
but if we did, that would probably be the character
although that would be fun
I have keywords with |
in them (no joke) :rolling_on_the_floor_laughing:
> just because you can, doesn’t mean you should
Hi, I am using carmine
. How do you handle single connection pooling? I want to have a connection pool at the same time I don't want to use the wcar* macro
since I prefer to not use global state, I want to do something like: (transact conn body)
.
@jarvinenemil we ended up creating a Component for that
this way we can setup one connection/pool in the system and pass it around without using any macros
I see, I will be going a similar route
thanks ✌️
that would be great!
https://gist.github.com/lukaszkorecki/0a3233e29b7ce6d8dc24ec68255c769b (an excerpt from the readme)
Why is it the this code
(defn test1
"Upload the file from S3 to the database"
[]
(let [a 5]
(map
(fn
[x]
(let [five 5]
(println "inside let block")))
[1 2 3]))
"done")
will not end up printing "inside let block" but this code (same as above, just without the "done" return value) (defn test1
"Upload the file from S3 to the database"
[]
(let [a 5]
(map
(fn
[x]
(let [five 5]
(println "inside let block")))
[1 2 3])))
will?because map
is lazy
- in the first example the map'ed sequence is thrown away and "done" returned
- in the second example the map'ed sequence is returned, and then the P in REPL tries to print it, and ends up realizing the lazy sequence
Oh wow oh wow. That caused me such heart ache trying to figure out why everything had suddenly broken. Thank you!
mapv
is a quick drop-in replacement that is eager
A while ago I started work on a Git pre-push hook in Bash and Planck with the idea of allowing everyone in a team to use whatever indentation they like. It’s probably alpha quality at the moment. If there’s interest, I can look into tidying it up and getting it into a state where other people could use it with some confidence. If you think you might find it useful, or if you think it’s wrong-headed, please let me know! Some details: • After pulling, you indent the code as you like. (To make things easy for me, I added an Emacs command to re-indent all Clojure and ClojureScript files in a project and create a whitespace-change commit.) • When you push, a hook rewrites commits to use the canonical indentation. This is done with cljfmt, using options that only change indentation. (This could be made more flexible — it doesn’t have to be cljfmt.) • Any commits that only change indentation are discarded. • After the rewritten commits are pushed, a new local commit is created with your local indentation. • It takes care to keep your untracked files, worktree and staged files as they were. (That was pretty fiddly.) For anyone super-interested, there might be enough information in the README to give it a go. If not, ask me questions. It’s at https://github.com/simon-katz/nomis-git-formatting. It’s been tested (a while ago) with: - lein-cljfmt 0.6.4 - Leiningen 2.9.0 - Git 2.16.1 - Planck 2.19.0 - Clojure 1.10.0 - Bash 3.2.57 (which is really old, but it’s what comes with macOS; maybe I should upgrade) - macOS High Sierra 10.13.6
iterate
(def tile-ports #{:a :b :c :d :e :f :g :h})
(s/def ::tile (s/and map?
#(= (set (keys %)) tile-ports)
#(= (set (vals %)) tile-ports)
#(every? (partial apply not=) %)))
I believe if you implement the Spec protocol yourself you can do that, but I don't think there is a lot of documentation for how to do that, and I don't think there is an easier way (like there is for attaching custom generators)
also I don't think that last every? predicate is helping. it will always be true by definition for a map
spec does include the name of failed predicates in errors, so if you pull the anonymous functions out and give them meaningful names it is at least slightly nicer
(defn valid-tile?
"Returns if the given object is a valid tile"
[tile]
(and map?
(= (set (keys tile)) tile-ports)
(= (set (vals tile)) tile-ports)
(every? (partial apply not=) tile)))
(s/fdef valid-tile?
:args [:tile any?]
:ret boolean?)
you might as in #clojure-spec, there may be some library that has an implementation of Spec that will let you customize the describe errors
Shouldn't that be :args (s/cat :tile any?)
(valid-tile? 3)
Execution error (IllegalArgumentException) at orchestra.spec.test/spec-checking-fn$conform! (test.clj:97).
Key must be integer
I would try defining named predicates for valid-keys? valid-vals? and no-self-mappings? for those three anon parts and then have (s/def :tile (s/and map? valid-keys? valid-vals? no-self-mappings?))
and see how that works.
(valid-tile? "a")
Execution error (IllegalArgumentException) at orchestra.spec.test/spec-checking-fn$conform! (test.clj:97).
Key must be integer
(that's still with orchestra BTW 🙂 )
user=> (valid-tile? 3)
Execution error (IllegalArgumentException) at user/valid-tile? (REPL:5).
Don't know how to create ISeq from: java.lang.Long
user=>
(defn random-tile
"Generates a random tile"
[]
(let [shuffled-ports (shuffle tile-ports)
pairs (mapcat (juxt vec (comp vec reverse))
(partition 2 shuffled-ports))]
(into {} pairs)))
Syntax error macroexpanding clojure.core/defn at (tile.clj:34:1).
#object[clojure.spec.alpha$and_spec_impl$reify__2183 0x782df094 "clojure.spec.alpha$and_spec_impl$reify__2183@782df094"] is not a fn, expected predicate fn
i saw in the code there is a mapping of some builtin predicates to generators for them
spec has some built in mappings from predicates to generators, but you can also combine your custom predicates with generators
regex ops are a particular set of spec combinators that build specs out of specs, that behave similar to regex operations, but on sequential collections instead of on strings
but all the combinators (not just the regex ops) will generate examples if the base specs they are built out of can generate examples
Finally, we can use alt to specify alternatives within the sequential data. Like cat, alt requires you to tag each alternative but the conformed data is a vector of tag and value.
regex ops describe the structure of a sequential collection
like regular expressions describe the structure of characters in a string
no, it doesn't. But I am the author above of the text above so... :)
but I am happy to make it clearer if I can
i understand that i can test a collection where i expect an int and then a string like this
short for catenate (base for concat, etc)
and once i step outside of the golden path of spec supported stuff it feels like i am missing something
like, i can use cat and keys to make specs that test if a collection fits some condition or that some keywords in a map fit
when evaluated, the form above returns a spec object
the spec api methods mostly take a spec and a value, then check whether the value is valid according to the spec
(with varying behavior - valid? returns a boolean, conform tells you why it matched, explain tells you why it didn't match, etc)
but like in this scenario - which i will admit is pretty toy - a custom predicate I write isnt a spec
predicates (function objects) are also valid specs
well, it can act as one, but it doesn't have the same error reporting magic that other specs have
generators don't affect the error message
so a "spec"
spec -> predicate || namespaced keyword reference to a spec || a "spec" object
there are several different things happening in the impl here, which adds some confusion here
spec 2 is much more regular in this regard
the spec forms (s/and etc) are really two things
they are macros, and they are also symbolic forms describing a spec operation
when evaluated, they return the spec object implementing the form
predicates (symbols that resolve to vars referring to functions) are evaluated in the course of that expansion and turn into function objects
function objects are opaque and as such are a bit more challenging to produce good errors. there are some hacks in the impl there to work backward from the function objects.
the way explain, which is what prints the errors works, is it walks down the spec building and path and when it hits some that doesn't match it uses the path it built down to the point for the errors. which means it is easy to report the point of error for "local failures" that are just about a value at the bottom of the spec, but you want to take a higher level failure "checking these values against each other" and report more path information which doesn't exist (because the check happens higher in the tree)
so you can't use spec's path builder for the error message to include the more local information, because the predicate operates at a level higher then that, so in order to make it work you need to implement the Spec protocol yourself, get the built path passed from spec, then generate your own extra information
which I would not recommend
well, I wouldn't recommend it in spec 2 either :)
there are also terrible ways you could write local predicates that operate based on that higher level knowledge, e.g. something with binding
your suggestions are getting worse :)
spec bottoms out at predicates and the level of feedback you can provide is pass/fail
one idea that has been raised is that instead of a simple "invalid" code you could provide a map with more useful information
I am definitely very interested in this. Returning more info than just true/false would greatly improve errors.
Example I ran into a few days ago:
We have a spec with a s/and
predicated called no-metric-cycles?
. It does this:
(defn no-metric-cycles?
[metrics]
(not (boolean (find-cycle-in-metrics metrics))))
It's transforming rich info about an error into a simple true/false value. I'd be much more interested in seeing the result of that find-cycle-in-metrics
function.i wish i had advice on how to make the docs clearer, but im not even clear on what it is that confuses me at any given point
feel free to log issues at https://github.com/clojure/clojure-site/issues if you can