This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-10-24
Channels
- # announcements (1)
- # aws (140)
- # beginners (41)
- # calva (47)
- # cider (43)
- # clj-kondo (36)
- # clojure (178)
- # clojure-europe (12)
- # clojure-gamedev (2)
- # clojure-italy (1)
- # clojure-nl (17)
- # clojure-russia (3)
- # clojure-spec (37)
- # clojure-uk (97)
- # clojurescript (173)
- # core-async (16)
- # cursive (18)
- # data-science (2)
- # datascript (6)
- # datomic (32)
- # dirac (16)
- # duct (16)
- # events (2)
- # figwheel-main (7)
- # fulcro (8)
- # graalvm (18)
- # immutant (3)
- # joker (2)
- # kaocha (8)
- # nrepl (6)
- # nyc (2)
- # off-topic (62)
- # quil (3)
- # re-frame (18)
- # reitit (6)
- # ring-swagger (1)
- # shadow-cljs (119)
- # spacemacs (4)
- # specter (2)
- # tools-deps (10)
- # vim (58)
- # xtdb (9)
Hey folks, how are you dealing with consistently and automatic code formatting in your teams (assuming that people are using different editors/IDEs)? I'm wondering if is there out in the wild something similar to lint-staged (https://github.com/okonet/lint-staged) for Clojure code formatting.
https://clojars.org/formatting-stack (released on Clojars only - not on github yet) uses exactly this approach - integrating git strategies (staging area, or a diff across branches) with formatters/linters. Looking forward to a release in December 🙂
@U45T93RA6 thanks for sharing it... Great lib you had over there. I'm wondering if you have a few configuration examples around so we can spike around it as well? If it help to solves our inconsistency code formatting issues here in Atlassian we'll be more than happy to contribute to the lib! 🙌
oh, ace to hear!
yes, will be happy to have "private alpha" users outside of work.
if you download and uncompress the .jar (`[formatting-stack "1.0.0-alpha9"]` is the latest recommended version), you'll find a quite detailed README over there. There's also a (private) wiki, but you can live without it - there's nothing crucial over there.
The recommended ways to use formatting-stack are described in README's Component/Integrant integration
and Reloaded Workflow integration
. Btw, since we don't use Integrant at work, so that specific integration might be lagging behind (can fix!).
tldr:
• in the Component system of a given project, you can place a formatting-stack.component/Component
, and that's it. Reformatting will happen on (reset)
, observing git status
• you also can use this as an IDE snippet: (clojure.tools.namespace.repl/refresh :after 'formatting-stack.core/format!)
. That helps in smaller projects that may not be using Component/Integrant.
• And, you can also refer some repl helpers in your user.clj/dev.clj: https://github.com/nedap/speced.def/blob/afce350c00f2673c9210d9e6aacc3c5a0d22e2df/dev/dev.clj#L10-L12
We also are working on a CI integration (e.g. fail builds if formatters/linters fail, for the diff between $feature_branch and $default_branch). Might be ready this week
Hope that helps you assess the tool. Can answer any DM 🙂
@U45T93RA6 thanks again for putting time on writing this explanation... we'll take a look in the solutions out there and yours included! 😄
@wcalderipe The "Clojure way" of formatting is pretty uniform across most editors/IDEs I think -- and there's the community style guide.
There are linters but they're more about code constructs and some of the non-layout stuff in the style guide.
CIDER and cursive usually have some small differences. I think colin does a lot of work to be amenable to us folks stuck on a 1970s editor 🙂
@dpsutton I'm a bit surprised that Cursive doesn't use "standard" paredit/parinfer etc indentation?
@seancorfield There really is no standard, and formatting varies pretty widely in the wild.
This is the closest thing to anything that could be considered a standard, if only because it’s the only option which isn’t form-dependent: https://tonsky.me/blog/clojurefmt/
I'm a bit surprised to hear that -- I very rarely notice much variation across all the open source projects I work with. Perhaps there are small differences I just don't see at this point...?
I notice little differences in formatting between our code. Mostly in cases where the old version of clojure-mode I have gets it wrong.
Tonsky's post is hardly a "standard" given how much it disagrees with the style guide and how CIDER / paredit / parinfer generally work 🙂
I have an key binding that reformats the current buffer, and often hit it without thinking about it (old habits)
@hiredman maybe you're more OCD about code layout than me? 🙂 (and I thought I was pretty OCD 🙂 )
Ah, I usually ignore whitespace in git diffs 🙂
Oh man, my last team, we had tests that would fail if code wasn't formatted the "correct" way
I've been on teams like that -- in other languages.
So you would get build failures from the ci server, and I used to think that was cool
Life's too short to argue about whitespace and indentation, eh...
And things like 1-space vs 2-space list indents etc are the source of much debate: https://github.com/bbatsov/clojure-style-guide/issues/126. There are a couple of pull requests on the style guide repo trying to amend that.
I mean, it’s totally bikeshedding, my point is that it’s not really decided, and the style guide isn’t really gospel.
I had a PR on the style guide once, it got rejected, but to be fair I deleted all of it and replaced it with a sick Bruce Lee quote
I remember seeing that thread and just sort of rolling my eyes and getting on with my life ¯\(ツ)/¯
Thanks for your explanation and for the shared references@seancorfield @dpsutton @cfleming. I have see differences between editors and IDEs code formatting and it does surprises me that Clojure doesn't have an "one to go format" out there. Personally, I see code formatting as noise in PRs it does taking people away from what really matters.
If someone sends me a PR with spurious reformatting in it, I just reject it. Show some respect when you work on an OSS project: follow the existing style/layout when you submit proposed changes.
I did not write this answer but I feel it! https://www.quora.com/As-a-software-developer-what-are-some-red-flags-that-would-make-you-reject-a-pull-request-immediately/answer/Ben-Podgursky /cc @wcalderipe @dpsutton @cfleming from our discussion on Wednesday 🙂
Thanks for sharing @seancorfield, but unfortunately the page is responding with 404 for me. Maybe it's just a temporary downtime... I'll retry later!
https://qr.ae/TWHm1P try that link @wcalderipe
@seancorfield thanks, this one works :thumbsup: i agree with the arguments there, however, it shouldn't be difficult to automate this process to avoid the formatting discussion all over again every time someone new joins the team!
If I submit a PR to someone's project, I try hard to follow whatever style they're already using. My proposed changes aren't about the layout.
(I will say that if you have the "tabs vs spaces" wars going on in your language community, you're going to see a lot more wild formatting differences in PRs... Clojure's mostly "2 spaces" so that sort of thing seems much rarer... mostly 🙂 )
For all the power programmers wield, we still can’t let everyone use whatever visual layout and keep the central source in some normalized format. It’s always baffled me how we can’t separate presentation and storage in this specific instance, where we always go on about it everywhere else.
we like our text file based tooling too much! If we stored s-expressions in a database we could totally do loads of crazy stuff, but the tooling would be ad-hoc and language specific
it would be nice to get at least some macros as values/functions... for example, or
to provide a default in a map: (update opts :encoding or "UTF-8")
plumbing library has a bunch of useful functions - http://plumatic.github.io/plumbing/plumbing.core.html
thanks, but that was just an example of something that can behave both as macro and as function
you mean, added to clojure.core? Such additions are far and few between these days (saying no to an addition is temporary, saying yes to an addition is forever).
If that isn't what you meant, such a function is trivial to write, yes?
it's trivial, sure, so it's about addition to clojure language. I just thought that there are usecases for "soft macros", or maybe they should be called "inlineable functions", so they are both functions which you can have as a value and do optimized stuff like short-circuiting and not evaluating some args it all when called as is
Hi - sorry to interject current conversation, please thread replies on this message? I'm having issues with atoms and pr-str
, edn/read-string
... trying to figure out how to work around this:
Clojure:
(clojure.edn/read-string (pr-str (atom "hello")))
Execution error at user/eval61644 (form-init4368157810432879853.clj:1).
No reader function for tag object
ClojureScript:
(cljs.reader/read-string (pr-str (atom "hello")))
#error {:message "No reader function for tag object.", ....
Obviously because:
(pr-str (atom "hello"))
=> "#object [cljs.core.Atom {:val \"hello\"}]"
How do I get clojure and clojurescript readers to read this value properly? I can workaround it by actually introducing a cleanup layer, but I'd really rather not...you really can't send the atom itself over wire, since it has mutable state which won't survive to string/from string conversion. if you want to read edn as some value for exploration purposes, you should use default reader like that:
(clojure.edn/read-string {:default tagged-literal} (pr-str (atom 1)))
Immutable values make a lot of sense to serialize and deserialize over the wire, but things get murky fast for mutable things.
i.e. "properly" can become very tricky to define precisely.
@U0CMVHBL2 ye - you have a good point.. In my case I'm creating a derived atom and slapping it into my app state (which I'm sending off to record for later debugging)..
Need to revisit the implementation and see if I can slice in a cursor-atom for the derivative instead of creating a new atom
interesting - rum/derived-atom actually handles getting passed in an existing atom in the options... perfect.
All clojure function calls cause all args to be evaluated before the function is called. Short-circuiting is impossible via a function call, unless you use techniques like passing futures/promises/lazy-seqs as args.
yes the idea I've had is about extending the language itself, and probably not going to happen..
No worries. I've had plenty of ideas that are probably not going to happen, too 🙂
A question about class loader for importing java classes (in repl): Does it use the per-thread context class loader? The example on pomegranate home page just doesn't work for me:
(use '[cemerick.pomegranate :only (add-dependencies)])
(add-dependencies :coordinates '[[joda-time "2.10.4"]]
:repositories (merge cemerick.pomegranate.aether/maven-central
{"clojars" ""}))
The deps are indeed downloaded, and urls for the per-session-thread DynamicClassLoader did got updated to include the downloaded jars, so I can see pomegranate has done its part of the job. However, when trying to import the dependency I still got ClassNotFoundException
user> (import org.joda.time.DateTime)
Execution error (ClassNotFoundException) at java.net.URLClassLoader/findClass (URLClassLoader.java:382).
org.joda.time.DateTime
I inserted a breakpoint in the DynamicClassLoader.loadClass
(a conditional breakpoint so it only hits when the target classloader is invoked) , and it never firedIn "Programming Clojure" book, it is claimed that for Clojure the number 0 is True but when I tried it on the REPL (true? 0) gives me -> false Any explanation?
Even (= 0 true) gives me -> false.
Is this outdated material or something?
@arto.eg this exactly checks if the value is true
not truthy
So truthy has another check function?
so in clojure, falsy values are false and nil. everything else is truthy
probably surround your expr that you wanna run when truthy with a when-not
Great. Makes sense now! 👍
Is it a bad idea to use take-while on the output of pmap?
I'm expecting map but parallel, stopping after the first element that fails the predicate, in the sequence that map would do
I don't think pmap would give you that. I think it looks ahead, but I'm not certain.
it goes N at a time, so you may do some extra work beyond what you take
that seems inevitable for a parallel map and take
Thanks!
I solved this problem with (sort) but I am not satisfied. Is there a better solution?
It's restricted for this exercise as you can see in the red box.
It's restricted to allow beginners to think harder, which is good. But by using sort I just fooled the exercise so I wanted a better answer 🙂
I think this is a fine answer 🙂
Maybe I can become more specific.. I didn't think that using If conditions is Idiomatic.
So I wanted to know if there is a better clojure way than sort.
if you wanted to see the "proper" way to do it, I would just (source max)
at a repl and see what it does.
Never thought of that 🙂 Good point!
it's good to not do that at first when you're doing the 4clojure problems, but eventually you want to know "the right way" so that you can learn how you should do it
I remember when i first started the 4clojure problems all of my solutions had loop/recur... but I learned not to do that by studying the code in core.
It can be pretty dense, but it'll get easier and easier to reason about what the code is doing as you get better
Thanks for sharing that, because It's exactly what I tend to think when I start solving a problem.... and I am not happy loops come to mind first.
yeah, it's hard to get out of the mindset
though, loops aren't the worst ever
but eventually you start to see things in terms of reduce, map, etc
(p.s. try to do it with reduce
)
Sometimes I am not able to draw a line between destructuring and pattern matching but anyway I would probably prefer them from loops.
Yes guys I agree, I think I need to refactor my mind around reduce much more often.
It's a functional gem.
I should say "Single result after one pass over all N things".
I'm going to be the black sheep here and suggest that you don't study the internals of the core namespace - there are precious few exercises at 4clojure where you actually need that level of optimization, more often than not it's the knowledge of what's in the standard library that will be most helpful. And for that, http://clojure.org/api/cheatsheet is indispensable. 🙂
It depends what you're trying to get out of 4clojure. If you want to know exactly how you'd do it if you were making the same trade-offs as Clojure, then by all means go for it. If you're just letting it guide you to new parts of the core library, then don't bother.
I think the advantage of looking at the core library is just that it's a specific, obvious place to look. You won't necessarily need the optimizations that they make, but it's just something to look at at all.
when you're starting out it's not obvious where to look for code
I wish that 4Clojure would just show you some random solutions from people (when you haven't followed anyone yet) when you solve a problem rather than making you follow people first.
what should I do with warnings like this in JVM 11?
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by clojure.lang.InjectedInvoker/0x00000008003cb040 (file:/Users/borkdude/.m2/repository/org/clojure/clojure/1.10.1/clojure-1.10.1.jar) to method com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl.parse(org.xml.sax.InputSource,org.xml.sax.HandlerBase)
WARNING: Please consider reporting this to the maintainers of clojure.lang.InjectedInvoker/0x00000008003cb040
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
I think you can use --illegal-access=debug
to get more info about what is happening
it will often point to clojure here but only because the clojure reflector is involved
(and fwiw, "future release" here does not include at least up through Java 13, so not sure how serious that admonishment is)
That message is annoying because it prints to stderr. On prod app startup, this results in several lines getting logged as error messages. We have to implement custom filters to prevent those messages from triggering alerts.
anyone know a way to make (prn (quote (quote foo)))
print ’foo instead of (quote foo)
?
the only thing I can think of is a postwalk with a list -> string substitution, but even then that wouldn't quite work with prn...
I know there’s hooks via print-method, maybe I can mess with the print-method for List
user=> (w/postwalk (fn [f] (if (and (list? f) (= (first f) 'quote)) (symbol (str "'" (second f))) f)) [:a (quote (quote foo))])
[:a 'foo]
(prn for that prints the same string you see in the result)
why do you want to do that?
was looking at this SO question and assuming zprint was getting its base string from there. I may be wrong about that now I look closer though https://stackoverflow.com/questions/58308404/configure-symbol-quote-expansion-in-clojure-zprint
there actually is custom support in the clojure printer for printing code, don't remember if it does the quote translation
user=> (require '[clojure.pprint :as pp])
nil
user=> (binding [pp/*code-table* (assoc @#'pp/*code-table* 'clojure.spec.alpha/def #'pp/pprint-hold-first)] (pp/with-pprint-dispatch pp/code-dispatch (pp/pprint '(quote foo))))
'foo
you don't even need all that, there's some extra stuff for spec support in that (dredging out of my notes)
Is there any concise overview to clojure interfaces and protocols? I mean seq, seqable, reducible etc. My intent is to understand for example why implementing IReduceInit for io/reader allows to use it in the context of a coll (e.g. in sequence and eduction)
well, in general, Clojure is mostly implemented in terms of Java interfaces (and to a lesser extent, Clojure protocols). All of the core library is written to use those abstractions, not concrete implementations. If you know which things to fill in, you can make your stuff work like core stuff.
self reducibility is implemented in the (open) CollReduce protocol, which has a coll-reduce function
it's extended to IReduceInit/IReduce, which are Java interfaces that concrete Java classes can implement to hook into that protocol
if you're doing Java stuff, it's probably best to implement one of those interfaces. if you're doing Clojure stuff, it's probably best to extend CollReduce on your thing
Is there any news about updating the Clojure error messages? Any references to such news or it's not going to be implemented?
Which error messages? There were significant changes in both 1.9 and 1.10. I can't imagine the work there has completely finished either
Glad to here there was progress. But I am using 4clojure so I am not sure which version they're using. Maybe that's why.
Is it that hard to update it?
So a significant way behind. On the plus side you can usually copy paste code from 1.4 to. 1.10 and it works. Clojure is is very stable across versions.
The compiler should be backward compatible.
I don't actually know what the deal is there. Possibly just no one willing to maintain it
Does seem like the current codebase is using Mongo and some old web frameworks. Might be part of people's reluctance to take it over
I am willing to take over it, but since I am a beginner probably will not be able to.
(and then there's the cost of hosting it all)
For folks working on 4clojure problems, there is now a dedicated channel #4clojure
hey everyone, quick question. Is it possible to extend a Jvm type to support clojure functions like conj/cons/assoc
? In the same way of extend-protocol
?
is it a type you make and control? or an arbitrary thing?
if the former, then yes, by implementing the right interfaces. if the latter, then no.
the other approach is to wrap - reify the interfaces and implement over the instance
yeah I was thinking exactly of that. It might get dirty though but I guess it would work
you can see examples of this in various places, like bean
that's a proxy approach
which has pros and cons
hey why i cant bind model of a table to a atom with seesaw? Im doing sth like this (def model-atom (atom [:columns .... :rows ....]))
(bind model-atom (property :model table)
@carocad you can't since those aren't protocols, but you can make a protocol yourself if you want
(ns my.ns
(:refer-clojure :rename {cons core-cons}))
(defmulti cons (fn [head tail]
(type tail)))
(defmethod cons :default
[head tail]
(core-cons head tail))
(alter-var-root #'clojure.core/cons (constantly cons))
Possibly because Clojure core itself is direct linked?
clojure core is aot compiled and direct linkeed
so internal calls to cons will not see this redef
I did not write this answer but I feel it! https://www.quora.com/As-a-software-developer-what-are-some-red-flags-that-would-make-you-reject-a-pull-request-immediately/answer/Ben-Podgursky /cc @wcalderipe @dpsutton @cfleming from our discussion on Wednesday 🙂