This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-01-29
Channels
- # announcements (17)
- # aws (12)
- # babashka (27)
- # beginners (85)
- # bristol-clojurians (1)
- # calva (16)
- # cider (3)
- # clara (7)
- # clojure (80)
- # clojure-europe (13)
- # clojure-italy (19)
- # clojure-nl (2)
- # clojure-norway (6)
- # clojure-poland (1)
- # clojure-spec (31)
- # clojure-uk (61)
- # clojurescript (29)
- # core-async (10)
- # cursive (7)
- # data-science (1)
- # datomic (29)
- # docker (3)
- # fulcro (120)
- # graphql (16)
- # hugsql (2)
- # leiningen (17)
- # luminus (2)
- # off-topic (36)
- # other-languages (3)
- # pathom (13)
- # re-frame (12)
- # ring (2)
- # rum (1)
- # shadow-cljs (126)
- # tools-deps (56)
- # vscode (5)
(defmacro with* [bindings & body]
(when-not (vector? bindings)
(throw (IllegalArgumentException. "Bindings must be a vector.")))
(when-not (even? (count bindings))
(throw (IllegalArgumentException. "There must be an even number of bindings.")))
(if (empty? bindings)
`(do ~@body)
(if (= :defer (first bindings))
`(try
(with* ~(subvec bindings 2) ~@body)
(finally
~(second bindings)))
`(let ~(subvec bindings 0 2)
(with* ~(subvec bindings 2) ~@body)))))
@emccue nice! I wonder why cursive doesn't like it. I guess only certain keyword patterns are allowed?
This is the grammar Cursive uses:
(defn for-bindings []
(vector
(repeat
(alt (all (keyword :matching :let :into :modifiers)
(item :into :sub-bindings
(local-binding)))
(all (alt (keyword :matching :when :into :modifiers)
(keyword :matching :while :into :modifiers))
(any))
(item :into :bindings
(all (capture (alt (symbol :as :binding)
(vector :as :binding)
(map :as :binding)))
(destructuring)
(any :as :value)))))))
@cfleming dumb question, but does that code for specifying a grammar live somewhere other than within cursive?
Not a dumb question at all! No, it doesn’t right now. I have a long-term plan to open up all the macro support so that users like yourself can add support for macros that you develop or use.
I’m planning to have an open-source repo that Cursive users could contribute macro support to, sort of like DefinitelyTyped for TypeScript.
Sounds useful, I'm definitely interested when you are sure you have the public api down
I can live with some undefined symbols for a few years if it means that the eventual api is good
Unfortunately I need to do some internal refactoring first, and I never get to that bit - there’s always something else that seems important. This was some of the first code I wrote in Cursive, and it definitely needs some love.
I’ve rewritten the form parser but haven’t integrated that work yet. But that will allow much better language support than I have currently, things like allowing macro forms to customise how the completion works at particular points in the forms (e.g. in a :keys
destructuring only offering completions based on known keyword names, or in a :refer
in an ns
only offering symbols from the right namespace)
That :keys
completion would be so cool!! I have long been considering switching to the {:keys [:a]}
syntax purely for the keyword completion. The whole rest of the code base doesn't use that syntax though...
Is there any advantage to use clj + deps.edn over lein + project.clj? I am familar with lein and want to know if it is worth getting used to deps.edn in the future.
@austin021 A data point: we started with lein
back in 2011 at work because that's all there was; we switched completely to boot
in 2015; and we switched completely to CLI/`deps.edn` in 2018. Happy to chat via DM in more depth about it any time. I contributed quite a bit to that ClojureVerse thread that Andy posted.
Yeah, I looked through it and saw that! I will let you know if I have some questions. For now, I am looking at these options while doing a side project. So I am going to take the opportunity to try out deps.edn
I highly recommend everyone at least try the new CLI/`deps.edn` stuff as modern alternative to lein
/`boot` -- especially since it's official and part of the documented "getting started" process on http://clojure.org 🙂
As the author/maintainer of clj-new
and depstar
, I'm happy to answer any Qs on it 🙂
boot is something that doesn't seem to come up unless an open source project uses it. It looks like a bit of an overlooked middle child (no offence, boot people!)
@U04V70XH6 I'm curious, why did you move away from leiningen in the first place?
For me boot is a bit too dynamic, full of temptations
@UJF10JP8A I blogged about our switch from lein
https://corfield.org/blog/2016/01/29/rebooting-clojure/
When the CLI/`deps.edn` came out, I wrote a post comparing some aspects of the three tools https://corfield.org/blog/2018/04/18/all-the-paths/ but I haven't blogged about why we switched from boot
(because it was mostly about problems we had with Boot's fileset abstraction and the pod system)
Thanks Sean, that's really helpful - I'll take a closer look later. I was most interested as I've been using leiningen exclusively for the 5 years or so that I've been using Clojure. I've attempted the move to deps.edn a couple of times but each time find myself back with trusty leiningen eventually.
Quite nice in smaller footprint of tooling and way less machinery. Can easily target git deps rather than artifacts. On the build side lein is heavy but does a lot with that weight. Lein aims to be a project and dependency manager whereas clj is upfront about being just a class path builder and program starter.
More discussion on the relative merits of the two tools here: https://clojureverse.org/t/is-there-a-sales-pitch-for-switching-to-deps-edn-from-lein-in-2020/5367
sure, use your metadata!
(->> 'clojure.core ns-publics vals (map meta) (filter :macro) (map :name) sort)
- something like that
(-> ->> .. amap and areduce as-> assert binding bound-fn case comment cond cond-> cond->> condp declare definline definterface defmacro defmethod defmulti defn defn- defonce defprotocol defrecord defstruct deftype delay doseq dosync dotimes doto extend-protocol extend-type fn for future gen-class gen-interface if-let if-not if-some import io! lazy-cat lazy-seq let letfn locking loop memfn ns or proxy proxy-super pvalues refer-clojure reify some-> some->> sync time vswap! when when-first when-let when-not when-some while with-bindings with-in-str with-loading-context with-local-vars with-open with-out-str with-precision with-redefs)
try doing that kind of thing in Java :)
@austin021 A data point: we started with lein
back in 2011 at work because that's all there was; we switched completely to boot
in 2015; and we switched completely to CLI/`deps.edn` in 2018. Happy to chat via DM in more depth about it any time. I contributed quite a bit to that ClojureVerse thread that Andy posted.
Is there a way to tell when a core.async channel buffer is full or empty? I’m interested in using it to fill up entirely and flush entirely when it is full.
A solution to the first question would lead to check-then-act race conditions > I’m interested in using it to fill up entirely and flush entirely when it is full. Sounds like a strange requirement. Say the max capacity is 500. It can transition from 450 (stored ietms) to 451 and also from 500 to 0? Seems too asymmetrical/abrupt A dropping or sliding buffer would be more typical usage
Also is it okay using Thread.sleep inside a go block or is it more idiomatic to use a take on an async/timeout?
It's not okay to do blocking IO within go blocks These two items can save you some headaches: http://danboykis.com/posts/things-i-wish-i-knew-about-core-async/ https://www.youtube.com/watch?v=096pIlA3GDo
Bookmarked. Thanks
How do people typically deal with "feature flags" in Clojure?
Currently, we just use standard configuration keys as feature flags and then have bunch of if
s in the code.
This means they are global on/off (cannot be targeted to a particular user / customer segment) and requires application restart to name a few downsides.
It's also relatively hard to manage them and actually not forget to remove them later.
Do you have any tips for libraries and how to approach it in general?
I tend to approach feature flags (or at least the kind you are describing) merely as an authorization problem. That way one doesn't reinvent e.g. clojure.core/if
, or existing authorization techniques/libraries
Maybe within an authorization-related function you can have some rollout logic (e.g. "is the user ID odd?"), but that's it (as opposed to a more pervasive approach)
I read long time ago that feature flags should be not a boolean yes/no, but rather a percentage of affected users, so you can start rollout slowly and eventually increase it to all users
Not using it myself (in my clojure project just yet), but I know the frontend guys are using https://github.com/Unleash/unleash
There's a java client, should be easy to wrap or create your own version in clojure 🙂
wasn’t there a function in one of the core namespaces for string length?
I forget what it’s called
(count <string>)?
I guess I can just use count
if I don’t mind 4 or 5 branches being done first
I always used count but for some reason I thought that there was a function that worked on strings specifically and called .length
directly
well, I think (.length <string>)
also works. I'm too noob to accurately compare the two.
unless you have proof that it matters, I'd use count
It looks like, from a glance at the source (https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/RT.java), that count
is implemented as .length
for strings, anyway. So, the same.
this is the kind of thing that the jit gets real good at optimizing so the perf is probably less of an issue than you think it is
guessing what types/branches are taken in a particular chunk of code
Thanks. That was the part I wasn't following in the original question, so didn't understand what was being asked.
the jit keeps a statistical profile of call sites like this and can optimize the branch prediction
@alexmiller silly question, but how good is Java's JIT at predicting map lookups over time, for instance in protocol methods provided by extend-type
different case there - Clojure actually creates a per-call-site cache for protocol instantiations
but I think it's just 1-slot iirc so monomorphic will be very fast but polymorphic will fall into protocol resolution
generally direct implementations of protocols in deftype/defrecord/reify will be fastest (highly optimized by jvm), then external extension, then metadata instance resolution will be slowest
Hello,
I was looking for a way to destrucutre a namespaced keyword defined with the shorthand syntax ::foo
and figured that there is no entry for that in the documentation.
Example:
(defn plop [{::keys [foo]}]
(inc foo))
(plop {::foo 1}) ;; => 2
(defn plop [{foo ::foo}] (inc foo))
(plop {::foo 1})
does the trickYeah, we have a doc site issue to enhance some of that. The ::keys will work in the same namespace
Yes thanks @mccraigmccraig. It was more for the case where you have multiple keys like {::foo 1 ::bar 2 ::baz 3}
and that you don't want to repeat them all.
ah, yeah. i find i pretty much always prefer the longform destructuring syntax anyway because it nests and aliases nicely and i find code easier to read when there's just one type of destructuring around :man-shrugging:
Has anyone been using https://github.com/sunng87/slacker with ring? I keep getting arity exceptions when I try the example
I was using a too-old jetty, without async
So a Clojure protocol function can have a doc string. There is a library I am working with that has a protocol with several functions, and I am thinking about enhancing their doc strings to include notes on performance of the implementation. These notes are accurate for the implementation included in the library, but can at most be suggested targets if someone else chose to implement the protocol differently for another class later. Would it be reasonable to document the performance notes in the doc string as "for the implementation on class Foo, this function runs in O(n) time?" ?
maybe "for the reference implementation on class Foo this function runs in O(n) time, other implementations should aim for the same" ?
that way it's as much a guide to implementing the protocol as a doc of existing implementations