This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-01-31
Channels
- # announcements (22)
- # asami (19)
- # aws-lambda (4)
- # babashka (42)
- # beginners (43)
- # calva (28)
- # cider (1)
- # clerk (79)
- # clj-kondo (12)
- # clojure (47)
- # clojure-berlin (1)
- # clojure-brasil (1)
- # clojure-dev (12)
- # clojure-europe (40)
- # clojure-nl (2)
- # clojure-norway (5)
- # clojure-uk (3)
- # clojurescript (56)
- # clr (12)
- # conjure (8)
- # cursive (4)
- # datomic (78)
- # dev-tooling (6)
- # exercism (1)
- # fulcro (9)
- # hoplon (3)
- # jobs (3)
- # jobs-discuss (4)
- # lambdaisland (3)
- # leiningen (1)
- # london-clojurians (1)
- # lsp (125)
- # malli (32)
- # matcher-combinators (3)
- # nrepl (1)
- # off-topic (6)
- # pathom (39)
- # re-frame (13)
- # releases (2)
- # remote-jobs (3)
- # sci (7)
- # shadow-cljs (117)
- # sql (6)
- # squint (7)
- # tools-build (15)
- # tools-deps (12)
Hi I am new to clojure. I use emacs with cider. I am trying to setup a project for testing libraries and trying out stuff. I came to know about experimental add-libs
in clojure.tools.deps
but having trouble making it work with cider. I am unsure how exactly should I use (:require)
so that when I launch cider nRepl in emacs it automatically brings add-libs
in scope, so that I can use (comment ...) blocks later to hotload other libraries conveniently. Appreciate any help, thanks.
Have you added the alias to your user-level deps.edn
?
keep in mind that the add-libs branch is possibly in conflict with the recent versions of the Clojure CLI
but I am hard at work to make this a Real Thing (once I get past all the side quests :)
I'm still using tools.deps.alpha
with add-lib3
and haven't run into problems -- yet! -- but I am also explicitly loading both tools.deps
and tools.deps.alpha
to do that.
yes, that would be necessary
https://github.com/seancorfield/dot-clojure/blob/develop/deps.edn#L102-L128 is how I add t.d.a with add-lib3.
but good to know that works
No I am not using the alias. I was putting this directly in deps like
:deps {org.clojure/tools.deps {:git/sha "8f8fc2571e721301b6d52e191129248355cb8c5a"
:git/url ""}}
and then I am simply launching cider-jack-in-clj from the directory with deps.edn
it's probably best to make your own alias, not hijack :deps. and then of course, you actually have to include the alias if you want to use it
The add-lib3
branch still uses the old (alpha) names. You'll need what I linked to above. But I will also caution that you that this is experimental stuff and may be broken -- I use it a lot because I don't mind stuff breaking and I'm used to debugging problems...
Yeah I read that warning everywhere, but being able to hotload is just so convenient when learning and experimenting with new stuff.
I have done some common-lisp coding, am so used to ql:quickload
or asdf:load-system
.
so If I create an alias how to instruct cider repl to load that alias
Aliases are specified before you have access to a repl, by setting the emacs variable cider-clojure-cli-aliases
.
But I think your original question isn’t really cider-dependant. If you have the deps directly without any alias and just want to see it work, have you tried something like this?
(require '[clojure.tools.deps.alpha.repl :refer [add-libs]])
(add-libs '{midje/midje {:mvn/version "1.10.3"}})
Yes you are right I am trying exactly that, the issue is that I am needing to write the first require in the repl, but I was hoping there would be an easy way to have add-libs pulled into scope when the repl loads by default.
maybe my question is when cider loads the repl for a project is there a way to execute a script which brings some symbols into the default namespace.
There is, but I haven’t used it personally. You can try setting the emacs variable cider-repl-init-code
Its definition:
(defcustom cider-repl-init-code (list (cdr (assoc 'clj cider-repl-require-repl-utils-code)))
"Clojure code to evaluate when starting a REPL.
Will be evaluated with bindings for set!-able vars in place."
:type '(list string)
:package-version '(cider . "0.21.0"))
Thanks, I will try it and update .
For example, these are its default values:
(defvar cider-repl-require-repl-utils-code
'((clj . "(clojure.core/apply clojure.core/require clojure.main/repl-requires)")
(cljs . "(require '[cljs.repl :refer [apropos dir doc find-doc print-doc pst source]])")))
sure ty.
I recommend
1. adding an alias to include add-libs,
2. add a .dir-locals.el
file which Cider uses to start a REPL (or use the alias when starting a REPL on the command line),
3. create a dev/user.clj
to load add-libs at repl startup or just use add-libs via rich comment forms
https://practical.li/clojure/clojure-cli/projects/hotload-in-project/ has examples of using add-libs with projects
https://practical.li/spacemacs/clojure-development/project-configuration/ - has examples of setting up a .dir-locals.el
configuration for Emacs which I find the most convienient way to add an alias like add-libs
https://practical.li/clojure/clojure-cli/repl-startup/ - shows how to set up a custom user
namespace that can be used to automatically load add-libs on repl startup, with an example including add-libs
I'd like to define an exception - I have a ns
definition with the name of my exception in the name slot and with (:gen-class :extends java.lang.Exception)
in the attr map. I realize this needs to be compiled before I can use it in a catch. How is gen-class typically handled? Is this something I'd add to something within my deps.edn and then compile through clj
? Or is this a manual repl step with the compile
function?
Looks like this is what I am looking for https://clojure.org/reference/compilation
all Java exceptions support chaining, so it's definitely way easier to use something that exists (like RuntimeException) or the Clojure friendly ex-info instead
Hey guys, I'm new to Clojure. I am doing some hacker rank exercises and I wrote the following code, which I know is using def to set some sort of mutable state:
(def npoints (Integer/parseInt (read-line)))
(def pairs [])
(dotimes [i npoints]
(let [inputLine (read-line)
numS (clojure.string/split inputLine #" ")
pair (for [n numS] (Integer/parseInt n))]
(def pairs (conj pairs pair))))
(println pairs)
What are the dangers of this code? Should I use an atom instead? Once I read all the lines, I will not "update" the pairs vector anymore, and I'll calculate something with that data.if you are going to have mutable state, then an atom
is usually the way to go.
However, you can write this example without using an atom, def, or other mutable containers. I would recommend trying to write this example in a more functional style using reduce
. If you're familiar with recursive styles, you can also try writing it with loop
and recur
.
the code above is just the part which I read the inputs from stdin, the problem itselft can be done functionally
I see some parsing and grouping as well. You can generate a list of strings from standard in with:
(require '[ :as io])
(def lines (line-seq (io/reader *in*)))
It's not perfect since it doesn't handle cleanup, but it's unlikely to matter unless your program runs for long periods of time or is analyzing extremely large inputs.reduce
and loop
are also appropriate for dealing with I/O more functionally (rather than dotimes
, doseq
, def
, etc)
learning reduce
and loop
will help cover fundamental ideas for functional programming, but they aren't necessarily easy to get "used to" (at least they weren't for me).
line-seq already puts each line into a sequence for you, so it's much better to use that directly like recommended. If you wanted to do it yourself, you're better off first reading each line, and then processing them, so that you separate impure IO from pure logic, but it should still be done functionally:
(def lines
(loop [lines [] line (read-line)]
(if line
(recur (conj lines line)
(read-line))
lines)))
You can put that at the start for example, so lines
will now contain all lines read from the input.
This is just to show you, but line-seq would be much simpler:
(def lines
(line-seq (io/reader *in*)))
@U7RJTCH6J I actually don't think you need to clean up the reader her, because closing it would close the input stream, and *in*
isn't meant to closed.Also, in real code, re-def’ing a symbol over and over has a performance cost. I’m processing text files that are multiple GB, so this would definitely show up. It’s really not for that. It’s also unsafe for threads, as you have a global value that you’re updating, and while global variables are sometimes necessary, they are undesirable in most languages, even unsafe languages like C.
Another thing about the example code is that it’s clearly for the REPL, in that it’s stateful with the read-line
calls. For this reason, it’s often better to break up some of the phases and compose them.
Admittedly, there are caveats around that (e.g. processing files means either: a) loading it all into memory and passing it off; b) creating a lazy seq, but then the input stream MUST be kept open until processing is finished; or c) processing a line at a time, as is shown in the example)