This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
- # announcements (5)
- # babashka (105)
- # beginners (92)
- # calva (77)
- # cider (17)
- # cljdoc (8)
- # cljs-dev (8)
- # cljsrn (8)
- # clojure (274)
- # clojure-dev (25)
- # clojure-europe (5)
- # clojure-italy (6)
- # clojure-nl (7)
- # clojure-norway (3)
- # clojure-uk (108)
- # clojurescript (330)
- # code-reviews (4)
- # cursive (6)
- # datomic (37)
- # duct (5)
- # emacs (14)
- # fulcro (23)
- # graphql (1)
- # juxt (1)
- # kaocha (2)
- # leiningen (10)
- # malli (9)
- # music (1)
- # nrepl (12)
- # pathom (21)
- # pedestal (2)
- # planck (4)
- # quil (3)
- # reitit (29)
- # rewrite-clj (10)
- # shadow-cljs (82)
- # spacemacs (29)
- # sql (6)
- # tools-deps (19)
then, when the company realises your value, they'll beg to hire you back at x3 your current salary 🙂
(obviously the goverment replaced the tin with aluminium many year ago) (and then hushed it up)
https://github.com/Crissov/unicode-proposals/issues/188 despite popular public requests for this emoji, the govt is clearly holding this up to prevent the spread of this knowledge.
(let [results (db/find-starships)] (if (seq results) (println "resistance is futile") (println "engage")))
The api returns a vector...however, so long as a collection is maintained, it doesn't have to be a vector onwards.
Oh, I guess you are using it again in the actual code, else why check it for nil? Nevermind, ignore me 🙂
some-> is another fun way to do this if you don't need the intermediate name.
No problem. It's highly subjective and a little inane possibly, but I have this weird thing about trying to avoid
let if I can. It's a bit hard to articulate why, but I think it's probably because it's a feature that is often used as a way to 'hide' complexity. I see a lot of functions that begin with 5 or 6
lets. I've even seen nested let's more than a few times. If nothing else, it's a fun little intellectual exercise to try to come up with ways to avoid them 🙂
https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/not-empty can also be helpful
I used to be a fan of slave pestov’s factor back in the day… The dev env is pretty interesting: https://factorcode.org/ Plus like forth it has comparable meta programming capabilities to lisp.
not-empty is, in a very mild sense, a bit misleading because it sounds like it's a pure predicate, but it's not. It reads perfectly fine if treated as a predicate but looks a bit weird if used as in my
(some-> ...) example above I think.
seq is probably better if you are doing anything other than using the truthy/falsey properties of the return value.
In fact, i'd imagine that if
not-empty was created today it would be called
not-empty? and cast result to boolean.
It was a very deliberate choice in the early days… If you dig through the google group you can probably find the rationale…
Essentially though I think it boils down to:
seq is one of the most central concepts in clojure’s sequence library/design, and it is guaranteed to return
nil for any empty collection.
2. Collection’s aren’t themselves
seqs you ask a collection to give you a
seq on it.
3. It’s idiomatic clojure as in most languages to test for the presence of a value rather than its absence i.e.
(when thing ,,,) is usually more idiomatic than
(when (not no-thing) ,,,)
(if (seq coll) ,,, ,,,) is idiomatic. It’s also simpler than
seq, and more efficient, not that that’s important for most cases.
not-empty is very useful in threaded expressions where you want either the original thing (collection, string, etc) or
nil if it was empty.
We use it a lot in form data validation where we treat an empty form field (`""`) as "not provided"
seq will lose the collection type for sure; as do most sequence functions; as they all call
@seancorfield presumably you don't write that in terms of
blank? because you don't consider
" " as not provided?
We tend to do
(some-> req :params :the-field (str/trim) (not-empty)) -- produces
nil if field was not provided or was blank (zero or more whitespace, nothing else). Since we always want the field trimmed if it is present.
is function I almost always end up writing
(defn not-blank [s] (when-not (string/blank? s) s))
It's sort of a funny thing because people use
not-empty because it's considered more descriptive and clearer than
seq in the simple predicate case, but if anything it has behaviour that a little more obscure and subtle than
seq at a glance. Not to mention the fact that we do have both
empty? but we don't have both
(instance? clojure.lang.IPersistentCollection coll) explicitly...
@seancorfield was referring to the original part of the discussion on this. Seemed to be the argument was that
not-empty is more readable in the simple predicate case. Completely understand your way of using it but the behaviour you are leaning on there is definitely a bit more subtle.
Entirely valid, but not immediately obvious from the naming of the function I think, that's all.
re-reading my code, it does feel a bit strange that I have
not-empty for it can change (the result) depending on whether the collection is empty or not
@dharrigan There is a semantic difference. In both cases you'll get
nil if the collection is empty. In the second case you will always get a sequence if it is non-empty. In the first case you will get back the original collection (vector, list, whatever).
Yes, understood, in this case yes, not really bothered if it comes back as a list rather than a vector
@dharrigan could be worth considering whether it makes sense to have all of your db functions just return a seq. If you standardise on the idea that "no matching results" = falsey (i.e. nil), these problems disappear anyway.
If you need constant time lookup of result in particular index positions, fair enough but that's pretty rare I guess. Also you can do cursor style magic with lazy sequences and keep all that internal to the db namespace. Worth considering perhaps.
next.jdbc the default is vector of hash map for fully-realized result sets (you can use
plan to operate via
reduce without realizing the result set). So @dharrigan’s DB functions will return
 when there are no results (not
yes, that's precisely what is happening, an empty vector when no starships (they've all been assimilated by the borg via a nasty truncate statement!)
The reason is so that the returned type is predictably a vector so the following is guaranteed to preserve order
(into (jdbc/execute! ,,,) (jdbc/execute! ,,,))
If that could return
nil, then if the first query did not match, the overall result would be a list of the second query's results in reverse order 😞
@seancorfield Ahh, that's also pretty subtle, but makes sense. I haven't used the library myself but I get the reasoning there.
(I've been down this path before in production code where DB ops could return
nil and it was a mess -- I ended up with a lot of wrappers that did
(or (sql/execute ,,,) ) 🙂 )
Makes sense. I've done a fair bit with dynamodb where paginating results is the norm and so dealing with lazy sequences and batch loading is kind of the bread and butter but can absolutely see where you're coming from here.
> Where do you host your private JARs? Using JitPack https://jitpack.io/, it’s nice and it has low maintenance overhead. Sometimes it’s a bit fickle: for example, the way it works, it picks up the version of a JAR from a git tag or a SHA of your GitHub hosted repo. Which is fine, except, the JAR that you want, regardless of how you reference it, is not built by default, but only when you request it for the very first time. So if you push some build where you’re referencing the release, that was never referenced before, the build will fail, because JitPack will take time to build the release on the first invocation. But once it’s built, then it’s there and you can fetch it when needed. Sometimes, this fetching can fail due to … well, sometimes it just fails, no logical reason. But because you don’t have to host anything yourself, it’s a sort of thing you can tolerate. Looking at GitHub’s new offering, the package registry: https://github.com/features/package-registry Any of you played with it?
@wesley.hall because of resource handling (JDBC connections etc), it's easier to use
plan to reduce a result set (eagerly) which actually allows you to stream very large result sets out of the database lazily. Counterintuitive, I know, but that's JDBC for you 😁