This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-08-05
Channels
- # announcements (1)
- # babashka (5)
- # beginners (151)
- # calva (43)
- # clj-kondo (23)
- # cljdoc (1)
- # cljs-dev (6)
- # cljsrn (10)
- # clojure (60)
- # clojure-australia (1)
- # clojure-europe (26)
- # clojure-gamedev (14)
- # clojure-nl (1)
- # clojure-spec (10)
- # clojure-uk (80)
- # clojurescript (66)
- # clojureverse-ops (4)
- # community-development (7)
- # conjure (8)
- # datomic (15)
- # deps-new (1)
- # docker (27)
- # emacs (2)
- # fulcro (13)
- # honeysql (13)
- # java (5)
- # jobs-discuss (43)
- # lsp (121)
- # luminus (13)
- # malli (1)
- # off-topic (73)
- # pathom (12)
- # polylith (29)
- # practicalli (4)
- # re-frame (35)
- # reagent (44)
- # remote-jobs (5)
- # rewrite-clj (2)
- # sci (7)
- # shadow-cljs (125)
- # sql (4)
- # tools-deps (9)
- # xtdb (5)
Hello everyone! I start to learn Clojure and I found clojure koans, I love jetBrains products. I want to run clojure koan in cursive, but when I chose start repl I get empty repl without interactive koans I want to see questions like on first screen, but I see empty repl 2 screen How can I run koans in cursive to see questions? Thanks!
https://github.com/functional-koans/clojure-koans#running-the-koans
there is a line in README about how to start koans from the repl.
Execute (exec "run")
in lower-right part of your screen and enjoy )
Thanks a lot!
Hi! I have a hard time trying to detect input file MIME type with apache tika in my web app. I'm sending file to my app with curl ... --data-binary "@/tmp/path-to-file
, so it's not a multipart form. In a handler request body type is org.eclipse.jetty.server.HttpInputOverHTTP
. When I'm calling (io/copy request-body (io/file '/tmp/foo'))
in clj it works as expected.
When I'm trying to use org.apache.tika.io.TikaInputStream
on a body with tika facade it doesn't work:
...
(:import
(org.apache.tika Tika)
( TikaInputStream))
...
(def tika (Tika.))
(def tis (TikaInputStream/get body)) ;; also tried (TikaInputStream/get body)
(.detect tika tis) ;; also tried (.detect tika body); this doesn't work as expected -- doesn't return mime type as a string, but throws the exception:
exception dump: https://gist.githubusercontent.com/jehaby/a0e37044f81f0b405284ef1aba047807/raw/724735922886cff5c2f39b961416858c02ff966c/tika-exception
ps: this code works: (.detect tika "/tmp/some-file-in-fs")
upd:
I managed to get it working with this code:
...
(:import
(org.apache.tika.mime MimeTypes)
(org.apache.tika.metadata Metadata)
( TikaInputStream)
...
(def tika-mt-detector (MimeTypes/getDefaultMimeTypes))
(def empty-metadata (Metadata.))
(.detect tika-mt-detector (TikaInputStream/get body) empty-metadata)
But as I understand (TikaInputStream/get body)
stores whole request body as a file in server's temp folder. I wonder is there a way to avoid this?> But as I understand (TikaInputStream/get body) stores whole request body as a file in server's temp folder. I wonder is there a way to avoid this? on a normal server system (AKA normal linux setup) /tmp is not a disk file system, it's a chunk of RAM that's treated as if it was a file system
(if that has any relevance to your concern...)
Thanks! TIL.
Btw: is using tika for this task (MIME type detection) the best option currently? Are there some other ways worth considering?
In the tools.build documentation, folks refer to “function chaining at the command line” (https://clojure.org/guides/tools_build#_parameterized_build). What is meant by this? Is this a Clojure thing?
@wordempire I assume it's referring to "piping". I suppose it's just passing the output from one function to the input of another right? That's usually something every language has. Clojure makes this very easy to do because it's encouraged and easy to use collections (they are all seqs) as that in-between medium, and the core lib has a rich set of functions for working on them.
@drewverlee @wordempire For a brief while you could specify multiple functions to execute via -X
and it worked by threading, as if you said (-> params (my-func) (next-func) (another-func))
where the params
came from exec args and the command-line.
That was only available on the prerelease branch and was removed before the stable release. So with a build script, you can only invoke one function, but it can use ->
itself to call multiple functions.
See https://github.com/seancorfield/next-jdbc/blob/develop/build.clj#L41-L42 for an example.
Hello, is there a way to parseFloats in javscript? I have been trying js/parseFloat
but that seems to return me a javascript object (?)
clojure -A:cljs -M -m cljs.main -re node -r
ClojureScript 1.10.773
cljs.user=> (js/parseFloat "1.23")
1.23
cljs.user=>
Right - okay i'm a moderately confused as to why I can't seem to get it working when in re-frame. Guess js/parseFloat should work
cljs.user=> (type (js/parseFloat "1.23"))
#object[Number]
cljs.user=> (type 1.23)
#object[Number]
cljs.user=>
My example isn't amazing code but did this locally
(def test4 {:results [{:id 0 :objective-results [{:coverage-score "10.1" :p-median-score 2 :centering-score 3}]}
{:id 2 :objective-results [{:coverage-score "3" :p-median-score 6 :centering-score 1}]}
{:id 1 :objective-results [{:coverage-score "5" :p-median-score 2 :centering-score 1}]}]})
(update-in test4 [:results] (fn [e] (sort-by (comp :coverage-score first :objective-results) #(compare (js/parseFloat
%2)
(js/parseFloat
%1)) e)))
But when I do this in my app
(rf/reg-event-db
:sort-results
(fn [db [_ k]]
(update-in db [:results]
(fn [e]
(sort-by (comp :coverage-score first :objective-results)
#(compare (js/parseFloat %2) ((js/parseFloat %1))) e)
))))
assoc-in db path function
will just stick that function there, not call it on the thing in the map
((js/parseFloat %1))
looks like you're calling the floating point result there.
Right - think that flew in somehow as we were trying various things >< but still not the issue atm
fair. but one thing it gets very hard to help people when you cannot trust that the code here is representative of code you are actually running. I don't know how you are copying and pasting things that use different functions and random parentheses
no worries. trying to help of course 🙂 . Its just that if we aren't seeing code you are actually running we cannot help finding subtle issues
Did this in the end
(defn sort-results [results k]
(sort-by (comp k first :objective-results)
#(compare (js/parseFloat %2) (js/parseFloat %1)) results))
(rf/reg-event-db
:sort-results
(fn [db [_ k]]
(update-in db [:results] #(sort-results (get-in db [:results]) k))))
Probably need to refactor but it works for now The idea we were going for was this
(rf/reg-event-db
:sort-results
(fn [db [_ k]]
(update-in db [:results]
(fn [e]
(sort-by (comp k first :objective-results)
#(compare (js/parseFloat %2) (js/parseFloat %1)) e)))))
where I was thinking we can just feed in a function similar to how we can feed in inc
^ this doesn't workBut I think main issue was trying to do too much in a single update-in
. probably need to dissect it a fair bit to figure out where exactly was there an issue
Thanks for your help! @U04V70XH6 @U11BV7MTK
Do I need to pay much attention to spec2 at this point? I'm presuming I should just write everything using spec1 for the time being.
Here’s something I don’t quite get. From the docstring of empty?
:
Please use the idiom (seq x) rather than (not (empty? x))
And from the style guide at https://guide.clojure.style/#nil-punning
> Use seq
as a terminating condition to test whether a sequence is empty (this technique is sometimes called nil punning).
I don’t quite get it! What is the benefit here? This seems to obscure the intent.If you look at the implementation of empty?
:
(defn empty?
"Returns true if coll has no items - same as (not (seq coll)).
Please use the idiom (seq x) rather than (not (empty? x))"
{:added "1.0"
:static true}
[coll] (not (seq coll)))
You'll see that (not (empty? x))
is equivalent to (not (not (seq x)))
. The double-negative just cancels itself out.Many people disagree with that advice and prefer (not (empty?))
Use what you like more and perhaps stay consistent
Thank you for the feedback. I guess now that i read the source of empty?
I cannot unsee it…
render=> (if (seq [1]) :present :absent)
:present
render=> (if (seq []) :present :absent)
:absent
Eh, it seems a bit unnatural to me because it performs a transformation rather than just returning a bool.
There is nothing stopping you from doing (def present? seq)
obviously. And tbf I like that better. Although first
is fine too I think.
first
doesn't quite work the same.
render=> (if (first [nil]) :present :absent)
:absent
no worries. the language makes it quite easy to quickly define little helpers like this. one irritation might be that you can always reach for clojure.core/seq
but you will need to bring in your ns.utils/present?
helper for that to be widespread
not-empty
can be very useful when you want to retain the underlying type of the collection. Also for strings: (not-empty "foo") => "foo"
, (seq "foo") => (\f \o \o)
, (not-empty "") => nil
(not-empty [1 2 3]) => [1 2 3]
, (seq [1 2 3]) => (1 2 3)
But, yeah, you just get used to the fact that (if (seq x) ..)
is idiomatic Clojure.
I think I don’t really get nil
, not fully:
https://clojure.org/reference/data_structures#nil
I know how it is used, kind of, or rather I learn more about how it is used. But I don’t quite understand what it really means. It feels overloaded to me, but I suspect that is because I don’t understand it.
There is a lisp idiom, which Clojure embraces, called "nil punning". Many functions accept nil as a parameter and do something "sensible" with it. Your feeling that nil is overloaded is quite appropriate, because it kind of is.
Oh, I see that the thread started out with that term 🙂
As far as internalizing its use goes, my recommendation would be to just keep writing code. As you spend more time with the standard library, you'll get a better sense of how nils are handled and how it helps the various functions work together smoothly.
It may help to think of nil
as representing a "nothing", i.e., the absence of a value.
Thank you for the answers. I will take @U7ZL911B3’s advice and start being mindful about where nil
happens and kind of absorb it the sense of it. However when I think about @U04V70XH6’s suggestion that nil
means “nothing”, then I’m slightly confused, in the above discussion we talked about how seq
returns nil
when a thing is empty. But from my understanding of what an empty thing is this doesn’t make sense. In mathematics, relational algebra, set theory and such we talk about an empty set to be a distinct value right? (I don’t have a degree, self-taught, so my understanding might be wrong).
Is the advice that I should take it as “this is how Cojure does it” or is there some deeper connection, explanation, or maybe misunderstanding that I’m not seeing. I’m fine with either, just would help me to know.
in clojure nil
is two things in one entity- the lispy idioms around nil and collections / booleans, plus it has a very special status in the jvm (eg. you can't call methods on nil, even something as basic as .toString
(which clojure covers via special cases throughout the stdlib))
and you are correct, the lispy idioms around nil are not the mainstream way mathematicians deal with collections
(though in LISP's defense when a list is the only possible kind of collection, treating nil and () as the same entity kind of sorts that out, it just gets more complicated when you want actual collection types beyond lists)
Thank you @U051SS2EU! Would it help me to learn what the representation of nil
or null
is? Is there any?
it's a bytecode value
it's not an object of any sort, it's just the vm's marker for "nothing here"
right, it's a simple constant on the bytecode level
it probably ends up being a null pointer but even thinking about designs that assume that fact is a sign you are in trouble :D
Does it emerge from bytecode, or is it put there deliberately by a language implementation?
how precisely would anything emerge in bytecode without a compiler putting it there?
it might help to get more concrete - in a stack trace with an NPE, how did the NPE get there?
some operation resulted in an unexpected / unchecked null, which was passed down one or more layers of method call arguments until someone tried to actually use it as a value
Ok thank you for these! My brain runs in circles a bit, I think I might read up on that and investigate further.
clojure.core is peppered with code that special cases null so it can be punned eg. (str nil)
-> ""
(conj nil 1)
-> (1)
each of those is a defensive branch in the code
so most of the time as a clojure user you can assume clojure.core does the right thing and your code will work with that if you write code idiomatically
Ohhhh, I get it! The core lib protects us from nil pointer exceptions and we can count on that fact and write code that uses this knowledge
this is why we use str
instead of .toString
, conj
instead of .cons
etc.
Note that functions in clojure.string
namespace are typical examples of functions that blow up on nil
args
yeah - I really did mean clojure.core itself, the rest of stdlib is less nil safe
Right so getting in the habit of passing nil into functions at the REPL might be useful
@U01EFUL1A8M What's your background, prior to Clojure? What programming languages? I'm wondering if there's an analogy we can draw that might help you here.
Good ol' JavaScript! WAT? 🙂
I just asked myself “why not use next
” then I saw why: https://github.com/clojure/clojure/blob/clojure-1.10.1/src/jvm/clojure/lang/RT.java#L711
next just calls seq anyway 😄
I've managed to avoid JS for almost my entire career so I can't offer you any analogies there, unfortunately 😐
A lot of functions that operate on sequences (as an abstraction) call seq
on their argument so that they will work on concrete collections. map
, filter
, etc all do that.
With JS its incredibly messy. You use null
as the explicit absence of a value, but there is also undefined
when its, just not defined prior
But with Clojure I always assume that there are good reasons for things, so I ask these questions to really absorb what the meaning of things are.
https://clojure.org/reference/data_structures talks about how nil
and the various abstractions and concrete collections all fit together but I think you said you'd already read that?
nil
has long roots in Lisps -- and several FP languages that didn't go down the statically-typed path (a lot of the FP langs that were around when I was working in that area in the '80s all had nil
of some sort and it often stood in for both "nothing" and "empty (collection)").
I found another nice hint to my original question: https://clojure.org/reference/lazy#_the_victim_nil_punning
The whole article talks about why there is rest
next
, what they mean and how seq
became the empty list check of choice
Clojure's nil
is both the Lisp heritage and the Java heritage (of null
, as in null pointer
).
Oooh, that's a nice read! I don't think I'd seen that page before (but I vaguely remember some of it coming up "historically" on the mailing list, years ago... back before Slack 🙂 ).
in scheme the cdr of an empty list is nil, just like the next (which calls seq) of an empty list is nil. rest
needs to return an empty seq, rather than nil
so it doesn’t need to evaluate the thing, so we end up with seq
for a check of whether a thing still has stuff in it.
The next
/`rest` thing is pretty subtle. We have just four calls to next
in our entire codebase (115k lines), compared to 63 calls to rest
it seems.
i default to rest for sure. and i forget which one calls seq. it's just not ingrained in me for some reason
And two of those next
calls should probably be rest
calls instead and the check in the loop
changed to call seq
.
(loop [servers ws-servers]
(when servers
(or (lookup-places-on-server (first servers) params)
(recur (next servers)))))
(`ws-servers` is never empty but that's not necessarily a good assumption)Right, so I always assumed that rest
is the default thing too, but it very much is an optimization for laziness.
I feel like the option type is very useful in languages that have very strict semantics, where you want to be forced to follow every branch. I dabbled in Rust a bit and there it felt really fitting for the language.
In Clojure this wouldn’t nicely fit. We have sets and keywords to achieve the semantics of that, but we stay dynamic and open.
I spent way too much time on this for today 😄 For some other time I found this talk on infoq from Tony Hoare, might be interesting to put NULL in historical context: https://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare/ Ty again for the help and discussion!
I think I don’t really get nil
, not fully:
https://clojure.org/reference/data_structures#nil
I know how it is used, kind of, or rather I learn more about how it is used. But I don’t quite understand what it really means. It feels overloaded to me, but I suspect that is because I don’t understand it.
Hello 👋 How can I define a custom generator only on CLJ but keeping the definition of the spec on CLJ and CLJS?
(s/def ::foo
(s/with-gen (s/nilable map?)
#(gen/fmap foo (s/gen ::bar))))
(s/def ::foo (-> (s/nilable map?) #+:cljs (s/with-gen ...)))
or whatever the syntax for those conditionals is
So in Compojure land I destructure a request into its URL params... but apparently some of them are passed in as nil
so is there a way I can do "default values" for query params that are not set?
Thanks I'll check that out. For now I did something like:
(let [token (if (empty? token) "" token) ...]
Are you talking about the {:or token ""}
bit?
That is cool and I had not noticed that before.
something to keep in mind is :or
in associative destructuring doesn't behave like clojure.core/or
, rather it behaves like passing a default value to get
user=> (let [{:keys [a] :or {a "foo"}} {}] a)
"foo"
user=> (let [{:keys [a] :or {a "foo"}} {:a nil}] a)
nil
user=>
(defn f
[{foo :foo :as m}] ;; <- can i stomp/shadow `foo` for arbitrary `m`?
...)
with-redefs
needs a known var, i think
(f {:foo "this is an arbitrary value here"})
you just call the function with whatever you want
i could. maybe a better question is, can i with-redefs
local bindings
right on, thank you
the only safe way to use with-redefs is stubbing for testing, and even that is only safe in a limited way
with-redefs was introduced when clojure stopped making vars dynamically bindable by default because people had been using the dynamic bindability to mock things in tests
it is not thread safe, the redefs are visible globally, and the way it sets the var back to the original value at the end is not safe on multiple threads, it is a race condition
I think something that be nice is to update most of the doc for core functions to add info about if they are thread-safe or not. Java tend to do that and its quite nice,
the list of non thread safe functions is pretty small and probably deserves to be its own doc: • things that use volitiles • things that use transients • things that use stateful transducers • with-redefs • proxy-super (there's probably a few others I forgot off hand)
for production code i'd use dependency injection
this is just fooling around
@michael740 not sure if I understand your question tbh, but does this help?
(defn f
[{foo :foo :as m}]
[(let [foo 1]
foo) foo])
(f {:foo 2}) => [1 2]
no, i was hoping to just overwrite foo
without touching the function f
. to be able to use f
as is. but thank you!