This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-04-21
Channels
- # babashka (16)
- # beginners (182)
- # calva (13)
- # chlorine-clover (43)
- # clj-kondo (17)
- # cljs-dev (14)
- # cljsrn (19)
- # clojure (97)
- # clojure-argentina (7)
- # clojure-dev (45)
- # clojure-europe (7)
- # clojure-germany (5)
- # clojure-nl (4)
- # clojure-portugal (4)
- # clojure-romania (5)
- # clojure-spec (46)
- # clojure-uk (21)
- # clojuredesign-podcast (2)
- # clojurescript (159)
- # conjure (28)
- # core-async (7)
- # cursive (13)
- # datomic (17)
- # defnpodcast (9)
- # duct (1)
- # fulcro (45)
- # graphql (6)
- # jobs (7)
- # jobs-discuss (1)
- # juxt (3)
- # kaocha (4)
- # leiningen (12)
- # malli (5)
- # observability (1)
- # off-topic (50)
- # pathom (15)
- # re-frame (16)
- # reitit (5)
- # remote-jobs (21)
- # ring (7)
- # shadow-cljs (166)
- # test-check (6)
- # tools-deps (27)
- # xtdb (2)
@sunchaesk It depends what you mean by that. Do you want to create a static website using Clojure-based tools? Or do you mean a web server that renders HTML pages from server side? Or do you mean a Single Page Application that renders everything client-side?
@sunchaesk I'd check out the #luminus documentation, and see if that fits your needs. https://luminusweb.com/
clj-kondo suggests I use (seq x)
rather than (not (empty? x))
. That sounds like bad advise for me. asking whether something is empty is much clearer than asking whether it is a sequence. at least in my opinion.
empty?
is basically (not (seq x))
so you'd be saying (not (not (seq))
which is pointless
this recommendation comes from clojure.core itself https://github.com/clojure/clojure/blob/master/src/clj/clojure/core.clj#L6208
you're free to (def not-empty? seq)
but come on
also seq
does not tell you whether something is a sequence. you have other functions for that, such as coll?
or sequential?
I find it bizarre. what does seq
stand for?
Anyway, if the language recommends using (seq ...)
rather than (not (empty? ...)
, shouldn't the compiler just do that for me?
this is a style recommendation, technically it will be fine but it's just poor style. the compiler has no business with that
you are also free to uppercase all your fns like (defn DO-STUFF)
and the compiler won't judge but....ugh
Joel, sorry I don't mean to be argumentative, but if the recommendation is there because (not (not ...)) is inefficient, then it seems to me that it is precisely the compiler's responsibility do take care of trivial optimizations like that.
In my opinion, (not (not x))
in a Boolean context, should compile the same as x
.
just because perhaps the compiler will reduce your (not (not (not (not (not...
function to just not
, it doesn't mean that your code is well written, or readable to others
Since you bring readability, I am also in the camp that (not (empty?
is more readable than (seq
. I tend to flip the if and else part sometimes just to avoid making this decision.
(if (empty? coll) ... ...)
the logic is now circular. Is (not (empty? ..))
poor style because it is equivalent to (not (not ...))
or because it is difficult for a human to understand? If the former, then the compiler should handle it in its optimization stage, if the latter, then I'd diagree. Asking whether something is not empty is a very understandable expression in every human language I know of. On the other hand I've never heard of a human language where a person asks the emptyness of something by asking seq
hah well, I agree with the docstring that (not (empty? is pointless and for me it's more difficult to parse. I know what seq
does as it's a core part of clojure. for (not (empty?
I need to think about empty?
and then negate it
@U010VP3UY9X you can argue about names in Clojure, but they are not going to change. Clojure has a strong philosophy of not making breaking changes. Another one that confuses people is contains?
. Just take it as a given and move on I'd say if you don't want to waste your time
the difference between empty
, empty?
some?
and some
(all of them very common) can be a pain for newcomers I think
As a newcomer it would be useful to collect confusing names and blog about it (in a constructive/non-ranty tone preferably), so other newcomers can profit from it and don't have to spend their time on this a lot.
imagine using (not (some?
instead of nil?
😛 that's how I see (not (empty?
.
(`some?` is just (not (nil?
)
That's not the right analogy. (not (empty?
reads like English and is very easy to parse.
You can also use https://clojuredocs.org/clojure.core/not-empty which is not a predicate (returns coll / nil instead of true / false)... But seq
is idiomatic in Clojure
Joel, I agree with you in the extreme. If someone asks whether something is not false or not nil, (which is common in the scheme community). My code is set-theoretic. I'm using sequences to represent data and I want to know whether the set is empty or not. i.e., "set" in the mathematical sense, not the clojure sense. Perhaps I should use empty?
and inhabited?
not-empty
is super useful to avoid passing empty collections around when you actually prefer to pass nil. so instead of checking in the users of the collection-producing function, you make the fn not return an empty coll
@U010VP3UY9X you're free to name the functions for your domain the way you want them to 🙂
At my old company, we had a proprietary lisp which is now some 30 years old, maybe more. The manual was full of advise for users to do certain things to avoid inefficiencies. I was never able to convince the R&D department just to make the compiler do those simple optimizations for me, rather than spending time maintaining tools and manuals for warning me about it.
@U010VP3UY9X Sometimes making optimizations means breaking existing programs. This is what Clojure avoids at all costs
@U04V15CAJ, yes I feel the same way. There is a balance, I understand, between being a good citizen, and making your code sane. I brought it up because I just started using clj-kondo as a linter. every linter is opinionated. I know when I've written linters in the past, my users often complained because they didn't agree with my advise.
@U010VP3UY9X to avoid checking for empty collections, you can append not-empty
at the end of your set-producing fns. say you have a find-users-by-pred
function. if no users are found, you want to return nil to, perhaps, return a 404 http error. so you do (not-empty (query-the-db...))
and there you go, it's either coll with users or nil
@U010VP3UY9X clj-kondo is a bit opiniated, but not stubborn: you can configure it and turn linters off if you don't agree with them. Even in clojure.core libraries I have found usage of (not (empty? ...))
btw
The doc string for empty?
says "Please use the idiom (seq x) rather than (not (empty? x))". It is a polite request, not a requirement. You can use (not (empty? Coll))
every day of the week, and twice on Sunday, if you wish. You will find many Clojure developers who do follow that recommendation and use (seq coll)
instead, and it is good to know what it means.
does clj-kondo fail if you use (not (empty? ...)) or just warn? this might be a tooling ergonomics issue
also (if (not-empty x) ...)
and (if (not (empty? x)) ...)
would behave the same in practice
I think seq
returning falsey for empty input is a common enough idiom that it makes sense to learn it if you are writing clojure, even if it looks odd
It definitely makes sense to learn it for reading and understanding other people's Clojure code, whatever you happen to use yourself. And if you are working on a team on a code base and trying to merge in changes to an established code base, do not be surprised if others prefer and request changes to use (seq coll)
instead of (not (empty? coll))
Then some form of this discussion can be repeated among the interested parties of that code base 🙂
If I refer to a function by full qualified name, do I need to use a :require
in the ns
declaration?
just a [clojure.string]
without any decorators?
(ns clojure-rte.dot
(:require [clojure.pprint :refer [cl-format]]
[clojure.java.shell :refer [sh]]))
(def ^:dynamic *dot-path*
"Full path to the graphviz dot program"
(let [m (sh "which" "dot")]
(cond
(= 0 (:exit m)) (clojure.string/trim (:out m))
:else "dot")))
What is the correct idiom for writing code which is OS dependent? I am using mac-os, and if my function is run on mac-os, then I know how to do a certain thing, otherwise I don't know. If someone every enhances my code, I'm happy for them to extend it to another OS. What is the correct idiom?
(defn dfa-to-dot
"docstring here"
[dfa & {:keys [title view]
:or {title "no-title"
view false}}]
(cond
view (let [png-file-name (str *dot-tmp-dir* "/" title ".png")]
(sh *dot-path* "-Tpng" "-o" png-file-name
:in (dfa-to-dot dfa :title title :view false))
(if (= "Mac OS X" (System/getProperty "os.name"))
(sh "open" png-file-name)))
:else
...stuff deleted
I don't know the Java API. and which shelling out are you referring to? For example, I don't know how to open a graphic file for viewing on non-mac. but on mac I just issue the open
shell command
There are two shell commands I need (or think I need). 1. run graph-viz dot
to create a png
file. 2. open it for viewing
I suppose there's a third OS dependency I have. I'm creating a file, and assuming a UNIX file system.
I guess it all depends how much you care about cross-platform here. But in theory, if you use the Java file APIs to create files and folders they'll handle different OS automatically
And you can use Swing to display an imagine on Java, which will also support cross platform automatically
For graphviz, I think there is a Java implementation of it, but I don't know how good it is
So, I'd say these are the "correct idiom". But in your case, having an if or cond might be simpler
I am not sure there is an idiom for this. Lots of things that create and run child processes will work on both macOS and Linux, like your example code, as long as the dot
command is installed. Windows tends to be different more often. Using the os.name
JVM system property is a good way to determine which OS you are running on.
after creating the png file, i'd like to display it. is there a better way than using a sub-process? anyway the "open" command has lots of problems.
Well, you can use one of the many Java GUI toolkits to display the png. That be one way.
in Common Lisp there is a convention to use (if ..)
either when there is a then/else part or when the return value is being used, and to use (when ...)
only for side effect, I.e., don't take advantage of the fact that (when ...)
returns nil
if the condition is false
. Is there any such convention in clojure?
So I think people would take advantage of the fact it returns nil to mean false on some cases
I was skeptical of this rule at first, but I liked it after I adopted it. it seems to help to express the intent.
I've heard people do the same in Clojure, but I think it's more common to stick to the less strict rule of just using when for elseless cases
clj-kondo
will warn if there is an if
without the else part. So it seems to suggest when
is not just for side effects, it is also an if
without the else
. Some people strictly use when
for side effects. There is no "rule" here.
I've definitely seen when
in the tail of functions used with lazy-seq
, where (when (more-elements x) (frob x))
implicitly terminates the seq by returning nil if more-elements returns falsey
I have a test case which generates some random data to test with. sometimes the test fail. Is there a way I can ask about the random number seed before running the test, so that if the test fails, I can print the seed, to help reproduce the error. It usually fails in the ci/cd pipeline in a situation where it is completely in batch mode. what is the model for getting the seed and re-seeding to the same place?
I am guessing Clojure will use the random related facilities from Java and if yes, there is no way to query the seed. However, you can seed it yourself and remember the seed.
Clojure's test.check library has methods to generate random data that uses a seed, and reports the seed in failing tests.
Also, Clojure's rand
function on Clojure/JVM calls JVM method random
in package java.lang.Math: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#random--
which is documented to behave on the first call is if it called java.util.Random(): https://docs.oracle.com/javase/8/docs/api/java/util/Random.html
The documentation for that Java class has a method setSeed
that allows you to assign a value to the seed if you wish: https://docs.oracle.com/javase/8/docs/api/java/util/Random.html#setSeed-long-
There is no need to ask for the seed, if instead you can force it to be whatever you want, which is of course also what you would want to do if you wanted to reproduce the random sequence again later.
Regarding setSeed
, it is much more common in Java to just pass the seed to the constructor new Random(seed)
. Setting it after you have used it a bit will break the "randomness", I think.
The documentation claims that it is a requirement that after assigning a value to the seed, the sequence of values returned is guaranteed to be the same every time.
If you have a counterexample to that, it sounds like a bug in the implementation.
Here is a sentence copied from the Java docs for the setSeed
method: "Sets the seed of this random number generator using a single `long` seed. The general contract of `setSeed` is that it alters the state of this random number generator object so as to be in exactly the same state as if it had just been created with the argument `seed` as a seed."
What I mean is, suppose I have seeded a generator with x and taken out 10 values and then re-seeded the same generator with y and taken 10 values, then if you view the 20 values together, that won't be random.
If you set the seed, I would think the only reason for doing so is because you explicitly want to repeat a sequence from a particular starting point.
If you call it at other times, then yes, you are shooting yourself in the foot.
So, you create different generators with different seeds. I have never seen someone use setSeed
.
I don't think that JVM package/class lets you create more than one instance of a pseudo-RNG. It is global to the JVM, shared by all threads, as implied by other statements in the Java docs of one of the pages I linked above. You are free of course not to use that class, as there are other pseudo-RNG implementations in Java readily available as open source, too.
The test.check Clojure library I mentioned implements its own pseudo-RNG in Clojure, if I recall correctly, and avoids using Java's.
Yes, you are right, I used the wrong words there. By "generator" I mean instances of Random
. I have never seen the seed of the same instance of Random getting updated using setSeed()
.
@seancorfield I was looking for something similar to flask in python. Nothing too complex. I think anything of the last two choices r the type I'm looking for
hey, is there any way to ignore that is-nil check? my method must return boolean.
(defn in-page? [page url]
(if-not url
false
(->> url
(re-matches (re-pattern (str ".*/" page ".*")))
(some?))))
and re-matches can throw exception on nil vals.I think you can just "flow" the nil
downstream.
(when url
...do stuff...)
If URL is nil
, the return from in-page?
will be nil
. The caller will treat nil
as false, that's how most of Clojure works anyways.having a question-mark
method, i'd expect* boolean as return
according to styling guide
Pred With Question Mark
The names of predicate methods (methods that return a boolean value) should end in a question mark (e.g., even?).
I see, hmmm
It is very common to use #{}
(a set) as predicate.
(remove #{1 3 5} (range 6)) ;; => (0 2 4)
But (#{1 3 5} [5]) ;; => 5
and (#{1 3 5} [4]) ;; => nil
. So, any value = truthy, nil = falsey.
No-one worries about types normally.heh 🙂
see the thread above
can also wrap it with some->>
(defn in-page? [page url]
(some->> url
(re-matches (re-pattern (str ".*/" page ".*")))))
some->> will not fix your nil issue. Maybe just attach http://clojuredocs.org/clojure.core/boolean in the end.
yes I'll add boolean
hmm it's not a url, just used for the example
or this
(defn in-page? [page url]
((fnil clojure.string/includes? "") url (str "/" page)))
I think that fnil will do (without the nil as return)
Hi, Im reading the joy of clojure and I was confused about this part:
(defmethod print-method clojure.lang.PersistentQueue
[q, w]
(print-method '<- w) (print-method (seq q) w) (print-method '-< w))
what do you find confusing? you can just (print-method '<- *out*)
in REPL and see what happens
I haven't read Joy of Clojure -- it does not describe at all what print-method
is except for using it in that example code snippet?
I am not sure, but they may be assuming a level of Clojure implementation curiosity that you will search through the Clojure source code itself if you do not recognize something. It is not typically cited as a beginner level book on Clojure.
I tend to read books standalone so it was not obvious reading it that print-method
was a clojure entity
@UJA8PA70W in general, clojure.repl (in scope in new repls by default) helps a lot:
(cmd)user=> (doc print-method)
-------------------------
clojure.core/print-method
nil
(ins)user=> (apropos #"^print")
(clojure.core/print clojure.core/print-ctor clojure.core/print-dup clojure.core/print-method clojure.core/print-simple clojure.core/print-str clojure.core/printf clojure.core/println clojure.core/println-str clojure.pprint/print-length-loop clojure.pprint/print-table)
(ins)user=> (find-doc #"\wprint\w")
nil
(cmd)user=> (find-doc #"\Wprint\W")
-------------------------
clojure.pprint/*print-base*
The base to use for printing integers and rationals.
-------------------------
clojure.pprint/*print-circle*
Mark circular structures (N.B. This is not yet used)
-------------------------
...
oh it's weird that clojure.core/print-method has no doc-string - is it somehow hard to give doc strings to multimethods?
there's always this
user=> (source clojure.core/print-method)
(defmulti print-method (fn [x writer]
(let [t (get (meta x) :type)]
(if (keyword? t) t (class x)))))
nil
but that just tells you the dispatch, not what it's for...
at least (doc defmulti)
is useful, I'm really surprised there's no built in doc for print-method though
Most likely that is a call to print-method
instructing it to print out the characters <-
to the writer w
So that when you print a PersistentQueue using that method, it comes out looking like <-2 3 5 7 11-<
<-
is a symbol, and it is quoted so that after evaluation, the result is the symbol <-
, without attempting to look up the current value of a Var whose name is <-
Just as if you wanted to quote any other symbol, e.g. (print-method 'foo w)
. Granted, <-
is a much less common sequence of characters for naming a symbol than the usual sequence of letters, digits, and dashes, but it is a legal symbol in Clojure.
I think the thing that confused me was not knowing print-method
was a clojure entity, reading the code it sort of looked like the function was calling itself.
noobie here! and struggling!
using the curl command work just fine (note sanitised)
curl -uXXXXXXXXyyyyyyyy1111111122222222333331111: https://api.example.com/search/qwerty\?q\=08887777\&items_per_page\=2
My code looks like -
(def co
{:URL https://api.example.com
:FUNCTION “search/companies?=”
:API_KEY "Basic "
:KEY “XXXXXXXXyyyyyyyy1111111122222222333331111”})
(let [RegNum “08887777”]
(try
(djson/read-str (:body (client/get (str (co :URL) (co :FUNCTION))
{:query-params {"q" RegNum "items_per_page" "2"}
:body-encoding "UTF-8"
:accept :json
:headers {(co :API_KEY) (co :KEY)}})))
(catch clojure.lang.ExceptionInfo……….
I have read lots of docs and my eyes are swimming now.
1. I understand the query string is "automatically" composed with the :query-params. This results in the \?q\=08887777\&items_per_page\=2 query string. Is this correct? The way I have laid it out is correct? This is because I did not quote my URL in a zsh so I can remove the \s: 'https://api.example.com/search/qwerty?q=08887777&items_per_page=2'
2. In the case of the equivalent of the curl -uXXXXXXXXyyyyyyyy1111111122222222333331111, which is a secret, :API_KEY is “Basic” and the KEY is “XXXXXXXXyyyyyyyy1111111122222222333331111”. There is no UID/PWD but secret in this case. Is this correct? clj-http was :basic-auth "Basic" and it was not :Headers
Learnt a lot about header that's for sure.
Double question apologies - but are related
Hi! Why am I getting nil but not 1 here?
(def prx (proxy [java.lang.Object java.lang.Runnable] []
(run
([] 1))))
(.run prx)
run
is void so your return value is ignored, maybe you want call
on the Callable interface - very similar but allows returning a value
user=> (def prx (proxy [java.util.concurrent.Callable] []
(call
([] 1))))
#'user/prx
(ins)user=> (.call prx)
1
@stebokas Because java.lang.Runnable/run
returns void
: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Runnable.html
If you proxy Callable
, its call
method can return a value: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/Callable.html
this is correct, but also weird why this macro let my implementation to return something. or at least write code as it appears...
there's no such thing as "returning something" explicitly in clojure - what would you expect clojure to do?
I guess it could error if the last line of your method isn't nil
?
I would expect to "return"/evaluate to 1 there
but you can't make a void method return something
Every expression in a function body is evaluated. Normally, the last value is returned, except for a void
function where nothing is returned, a.k.a. nil
.
void methods only exist via Java interop, they are not a "normal" thing in Clojure, so you're seeing impedance matching at the interface here
I'm trying to imagine what use case would require a callable and also require a return value when called
also - fn
implements Runnable and Callable so you don't need proxy
executors can use callables
(ins)user=> (.run (fn [] 12))
nil
(ins)user=> (.call (fn [] 12))
12
How to use 'this
in proxy
macro?
(def prx (proxy [java.lang.Runnable] []
(run
([] (println "0000" 'this) 1))
(toString ([this] (str "------" this)))))
(.toString prx)
gives me an error about arity. Documentation mentions 'this
but not clear how to refer at itthat toString is bad because str
already calls toString
don't use 'this
- that's a symbol, use this
it's an implicit binding (don't put it in your binding list either)
user=> ((proxy [clojure.lang.IFn] [] (toString [] "an anonymouns function") (invoke [] (str this))))
"an anonymouns function"
that implements IFn by returning its string, and implements toString with an arbitrary string
Dang… having to do non-clojure work without being able to use ->
is really hard
Is their a "transaction-like" mechanism for atoms, to allow composability of side-effect functions which use swap! ? in my scenario, the functions are operating on a single atom (it's a reagent atom). I have a single page application, and need to update ui-related data (tracking what was last clicked), and core data.
no, that's kind of the whole point of atoms
maybe you could use watchers, I don't know much about the domain
I mean, comp
can compose functions into a single function that could be given to swap!
true...i have to re-think the architecture. some of the side-effect functions uses reagent cursors to update only portions of a global hashmap. get's messy when you want to compose these functions to update different sub-trees of the hashmap.
i was trying to avoid sprinkling swap! around the code base, or creating two functions for side effect calls, one which performs the mutation, and one that wraps the mutation with a swap!
i feel like introducing channels could work to queue changes...but seems a bit hacky and could lead to some (minor) race conditions
have you looked at https://github.com/Day8/re-frame? it’s made to work with reagent and solve some of the state management issues you may be running into.
and the #re-frame channel is pretty helpful and active if you run into any issues
OK, guys - I’m trying to make the following code more efficient:
(def initial-state [{:b [], :i 0} {:b [], :i 0}])
(def st [:gc :gc :pc :pc :oc :oc])
(as-> initial-state $
(f $)
(update-in $ [0 :b] into st)
(update-in $ [1 :b] into st)
)
; => [{:b [:gc :gc :pc :pc :oc :oc], :i 0} {:b [:gc :gc :pc :pc :oc :oc], :i 0}]
The above works perfectly, but I was thinking the two update-in
lines could be more efficient. Aha, I said to my newbie self - here I could use my newly learned map
function! But that causes a problem, in that I get a double entry, with the first updating 0
and the second filling 1
:
(as-> initial-state $
(f $)
(map #(update-in $ [% :b] into st) [0 1]))
; => ([{:b [:gc :gc :pc :pc :oc :oc], :i 0} {:b [], :i 0}]
[{:b [], :i 0} {:b [:gc :gc :pc :pc :oc :oc], :i 0}])
Oof. Is there a way of doing this, and still preserve my as->
thread?how would map make this more efficient?
by more efficient do you mean less code? using map there will make it less efficient in terms of space and time, and less efficient in terms of time taken to understand when reading it as a human imo
Yeah, it just seemed a little klutzy having two lines of code that were almost identical. 😄
I didn’t know if there was a proper style that one should adopt as a Clojurist.
->
can safely replace the as->
since all functions in the chain accept the param in the first position.
I would say clojurists in general look suspiciously on removals of duplication/boilerplate that make the code harder to understand
@hindol.adhya I simplified the above example. There’s going to be more than this in the chain.
OK, I’ll just leave it as the “easier to read and do” version.
I still don't think map makes sense here - its shape of input and output don't match your domain
@noisesmith Hmmmm… :thinking_face:
I’ll keep it as-is. Thanks, guys! I was trying to be too clever. 😄
(reduce (fn [m path] (update-in m path into st))) initial-state [[0 :b] [1 :b]])
I think reduce actually matches the shape of what you are doing
(it's also a variant of "put the update-in in a function")