This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-01-30
Channels
- # announcements (14)
- # aws (2)
- # beginners (167)
- # calva (25)
- # cider (124)
- # cljs-dev (2)
- # cljsrn (7)
- # clojars (2)
- # clojure (113)
- # clojure-europe (2)
- # clojure-italy (6)
- # clojure-spec (30)
- # clojure-uk (90)
- # clojurescript (20)
- # code-reviews (16)
- # cursive (28)
- # data-science (2)
- # datomic (89)
- # duct (97)
- # emacs (4)
- # figwheel-main (12)
- # fulcro (37)
- # graphql (3)
- # java (3)
- # jobs (2)
- # juxt (3)
- # kaocha (37)
- # leiningen (2)
- # luminus (2)
- # off-topic (30)
- # onyx (2)
- # pathom (3)
- # qlkit (1)
- # re-frame (7)
- # reagent (2)
- # reitit (62)
- # remote-jobs (9)
- # shadow-cljs (26)
- # tools-deps (19)
- # vim (1)
- # yada (8)
What do Clojure folks call a single source file? For example in Python it's called a module. Presumably not a namespace, since I gather a namespace can be multiple files.
Mostly folks refer to a namespace since it's normal practice to have one namespace per file and one file per namespace.
There are occasionally reasons to split a namespace over multiple files (as clojure.core
does), e.g., for conditional loading of different code on different JVM or Clojure versions, but it is rare.
Thanks @U0KNSL85S and @seancorfield, that's good to know
It's also worth bearing in mind that Clojure's "unit of compilation" is a top-level form (s-expression), not a file.
And the compiler behaves very much like the REPL, reading and compiling (and executing) each form in a file sequentially as it is read in.
Right, that explains why I totally screw myself up when I duplicate a file but forget to update the ns
declaration.
Clojure require
forms, and :require
clauses inside an ns
form, if the namespace is not already loaded, look for them in your Java classpath at a file name computed from the namespace name. The Eastwood lint tool does a check very early on and aborts with pretty clear warning messages if it finds any file name <-> namespace name mismatches. https://github.com/jonase/eastwood
thanks @U0CMVHBL2, that sounds very useful
@U0CMVHBL2 do you happen to know of an eastwood equivalent for ClojureScript?
I do not know of one. You could try asking on #clojurescript channel to see if anyone there does.
I usually call it a source file
{:added "1.0", :special-form true,
:forms '[(fn name? [params* ] exprs*) (fn name? ([params* ] exprs*)+)]}
[& sigs]
(let [name (if (symbol? (first sigs)) (first sigs) nil) ===> binding function name
sigs (if name (next sigs) sigs) ===> binding fn params and body
sigs (if (vector? (first sigs)) ===> check if params is vector
(list sigs) ===> binding body to sigs
(if (seq? (first sigs)) ===>(need an example which make this cond be true)????
sigs ===> binding sigs to sigs
;; Assume single arity syntax
(throw (IllegalArgumentException.
(if (seq sigs)
(str "Parameter declaration "
(first sigs)
" should be a vector")
(str "Parameter declaration missing"))))))
Not sure what you're asking @quieterkali...?
This is for (fn name [args] body)
or (fn name ([args] body) ([args] body))
etc.
i wanted to know what is passed to the fn macro a be able to follow the execution path. so just the fact to know the argument being passed help a lot 😄
Ah, OK.
your explanation do helped a lot too. I am reading it carefully to make sure i got everything
(where name
is optional)
So the first sigs
in the let
will be either ([args] body)
or (([args] body) ([args] body))
so you have (if (seq? '[args]) ...)
or (if (seq? '([args] body)) ...)
-- does that help?
@seancorfield based on the kind of input fn
take, i haven't been able to see a case where this state will be hit (if (seq? '[args]) ...)
but in the first if
yes. am i missing something?
this (fn name [args] body)
`in the first if
and (fn name ([args] body) ([args] body))
etc.` goes in the second if
is it correct?
@seancorfield Can you also please take a look to this code and tell me why psig (fn* [sig]
? sig = sigs
? if yes, so how comes?
[& sigs]
(let [name (if (symbol? (first sigs)) (first sigs) nil)
sigs (if name (next sigs) sigs)
sigs (if (vector? (first sigs)) `([args] body)` or `(([args] body) ([args] body))`
(list sigs)
(if (seq? (first sigs)) `(if (seq? '[args]) ...)` or `(if (seq? '([args] body)) ...)`
sigs
;; Assume single arity syntax
(throw (IllegalArgumentException.
(if (seq sigs)
(str "Parameter declaration "
(first sigs)
" should be a vector")
(str "Parameter declaration missing"))))))
psig (fn* [sig]
;; Ensure correct type before destructuring sig
(when (not (seq? sig))
(throw (IllegalArgumentException.
(str "Invalid signature " sig
" should be a list"))))
I'm sorry, I don't understand your question.
please forget about my last question. i just saw the answer. i was being really stupid. thanks for your help 🙂
There is a map
operating with sigs
, which is being passed to fn* [sig]
right after the first IllegalArgumentException.
in the implementation
(so it's an error if the first element isn't a vector or a seq)
(since that first if
is actually handled by the (if (vector? (first sigs)) ...)
clause above)
Put the namespace on the keys — it displays the namespace outside the curly braces just to make it more readable.
How do I import java class from a java file? I see lein has ":java-source-paths" option, but how could I do this with deps & cli
deps/cli is for running Clojure code. You'd need to compile the Java separately and then add the (compiled) .class
files to your classpath when running the Clojure code that depends on it.
lein
(& boot
) are "build tools" and know how to do a lot more than just run Clojure code. There are plugins for both that let you use deps.edn
for your dependencies.
thx I did the way as you mentioned previously cause I prefer using deps & cli without lein and boot 🙂
@manutter51 am i supposed to do this by casting keywords to string, join and then recast to keyword?
Here’s one way you could do it:
(def m {:foo 1 :bar 2 :baz 3})
=> #'user/m
m
=> {:foo 1, :bar 2, :baz 3}
(defn add-ns [m new-ns]
(reduce-kv (fn [m k v]
(let [new-k (keyword new-ns (name k))]
(assoc m new-k v)))
{}
m))
=> #'user/add-ns
(add-ns m "hello")
=> #:hello{:foo 1, :bar 2, :baz 3}
Hello, is there something similar like Linuxkit/Moby (Go) in Clojure/Java world? I didn’t find with Google. Or Buildroot/Yocto? (embedded system development)
Maybe https://github.com/nakkaya/ferret is similar a little bit.
I have a question about macros. I'm looking at the source code for clojures ẁhen
macro.
(defmacro when
"Evaluates test. If logical true, evaluates body in an implicit do."
{:added "1.0"}
[test & body]
(list 'if test (cons 'do body)))
Functions eagerly evaluate their arguments. It would be evaluated before the test was run and would return the result of the body if the test were true or nil in the alternate case
Clojure is not lazy despite what people might say. If the language were lazy --like Haskell--you could write this as a function
oh I thought it was only constructing one list, but actually it is a list within a list (if test (do body))
Does that pass the test suite?
I'm very green on Clojure, but I think that instead of reversing the list of ints, you could load them into a vector and use peek and pop for more efficiency. Someone will have to correct me if I'm wrong.
On the "double-two-by-two" function
is there a way to have all my clojure repls or namespaces or whatever have the doc
feature included? I find myself using it all the time and haven't figured out when I have access to it or not.
in a new ns (after your initial one) you can (use 'clojure.repl)
to access doc, etc.
there might be a trick to making sure clojure.repl is always in repl scope...
that's my hope. It's not a huge deal but just curious. Like if I create a new app in leiningen and start the repl, clojure.repl seems to work right in that namespace. but other times, I'll start a different repl, be in the user namespace and still not have the functionality
if you use CIDER, there is a menu accessed by hitting ,
(comma) in the repl that has require-repl-utils
that i use often
i wished the doc's and source macros worked with functions that are defined in your own namespaces. it doesn't seem to work like that
doc does, source only works if you load your code from a file (which CIDER doesn't do for typical workflows)
why wouldn't core doc definitions just be included by default on all namespaces? does it use any resources?
but you can use load-file
or (require 'some.ns :reload)
in the repl, after that source
works on things from that file
@chase-lambert the docs themselves are attached to the vars they document, it's a design decision that clojure.repl isn't automatically visible in every new namespace
cool. i'll work around it. no biggy. for some reason looking up docs as I learn doesn't take me out of flow. but seeing a unable to resolve symbol error instead makes my eye twitch
or stop switching namespaces, there really is very little reason that your repl's namespace should ever not be user
that's true. i'm realizing i switched a lot of my repls to use rebel-readline and it doesn't have the functionality included in it's user ns on startup.
that sounds like a good ticket for the rebel-readline project
sounds like it's already being discussed: https://github.com/bhauman/rebel-readline/issues/158
but sometimes when I start a lein repl it starts me in user or it starts me in something like my main file like clojure-noob.core ns. I haven't figured out when it does which
ultimately i think i try out too many fun looking tutorials and examples I find online and it gets me using too many repls or namespaces beyond my current understanding.
Your editor probably has a hot key to shows docs for the current symbol under the cursor @chase-lambert
(a recommended workflow is not to type into your repl but to stay in your code editor and type code there and evaluate it into the REPL with whatever hot key your editor uses)
Have you watched Stu Halloway's talks on "REPL-Driven Development" and "Running With Scissors"?
I think I did but when I was really fresh and just consuming all things clojure. Maybe now that I have a little time under my belt I can rewatch. I have tried to move my work flow to that but when I'm really digging deep into experimenting on a function I am still more productive just staying in the repl until I figure out what I'm doing.
My workflow has developed around using (comment ..)
forms in my code that contain what I would previously have typed into the REPL directly. That way you get full editor assist in writing your Clojure code, a history of your would-be REPL session, and it's easier to copy'n'paste your "scratch" code into actual functions and tests that you plan to keep.
Stu mentioned this exact same workflow in one of his talks and called such things Rich Comment Forms -- partly because it's what Rich does too 🙂
Do you know what talk this was from?
I think it was Running With Scissors... let me get the link...
His earlier talk: https://vimeo.com/223309989
Transcript https://github.com/matthiasn/talk-transcripts/blob/master/Halloway_Stuart/REPLDrivenDevelopment.md
(Running With Scissors doesn't have a transcript yet @U0CMVHBL2? 🙂 )
excellent, thanks
@seancorfield A very reasonable observation. I will consider creating one, but no promises on when. Will add an issue to that Github repo that may help remind me.
interesting! I have been seeing that (comment ...) thing in some clojure files I've been seeing lately.
In particular, at work, we tend to have a (comment ..)
form at the bottom of each file that contains various require
s and setup code (such as creating and starting Components) that make it easier to test/experiment with code via the REPL.
that makes some sense. what has been holding me back from this workflow is...like if you could see my repl history it's just crazy how much I need to explore around to figure a function. If that was in my source code it would be dozens of iterations and lines i guess just for one function.
I keep trying to improve my paredit skills though so I can just keep adding to the same function more quickly or something.
That's fine tho' -- while you're learning those (comment ..)
forms would become a series "notes to self" about how you arrived at a particularly solution, that should help with retaining the knowledge about each REPL session...
now, i am just going through various books and tutorials. Maybe once I really start trying to create my project I wouldn't be jumping around so much.
I find myself focusing too much on tooling and work flow instead of the actual exercises I should be doing though but I think I'm slowing getting better at the whole thing
I find I "jump around" a lot less when I have a (comment ..)
form containing all my notes/code about how I debugged a problem or built a solution -- and since it's all in the main editor window, I don't have to think about tooling or flow since I stay in one place and use one set of hot keys.
I've used quite a few editors over my nearly nine years with Clojure and my workflow has settled into using just a small handful of commands: evaluate (current) form, evaluate top-level (enclosing) form, load file, run all tests in this namespace, run this test, show docs, show source. Plus connect to REPL/disconnect from REPL (which I actually start manually outside the editor -- and I tend to have three or four REPLs running constantly, in different projects).
(lately I've added Cognitect's REBL to my workflow so I have alternatives for those two 'evaluate' commands that also submit them into REBL for visualization/data exploration)
huh, my comment blocks are usually short lived. I use them for debugging and delete them before committing
I like it. My other problem is testing out too many tools. I've tried to stay with emacs but it was locking up on my computer for some reason so I started exploring there too. I'm back to just trying to use emacs, cider, and using defaults for all of that as much as possible. Then I find a pain point while learning and let it take me off track by taking up all you folks time! hahaha
These days I'm use Atom + Chlorine and Socket REPLs http://corfield.org/blog/2018/12/19/atom-chlorine/
The main difference is that ProtoREPL used nREPL whereas Chlorine can connect to and upgrade a Socket REPL, which is really important for me.
@seancorfield I’ve no idea what the difference between nrepl and a socket repl is 😅
In terms of my core workflow, it's otherwise identical in Chlorine to what I did in ProtoREPL (partly because I submitted PRs to Chlorine for exactly the functionality I relied on from ProtoREPL 🙂 )
I see good things happening there. That's one good problem in the clojure community I guess. Cool tools from all angles. I actually like emacs and keep my init.el minimal but cider (or I assume cider but it may have been a coincidence) was locking up my emacs completely randomly. But when I try Cursive (way too heavy for me) or VS Code (I like Calva) I find myself wasting too much time re-learning instead of focusing on the programming.
@seancorfield not to start an 'editor war', but do you not have any issues with latency/speed of display or response time when opening files with Atom?
Yeah, I keep dipping into VS Code and Calva -- really good work going on there. @audiolabs Atom can be a bit slow with large files (1,500+ lines) but otherwise I don't find it to be problematic.
Ok, that's my experience as well. However 1,500 lines isn't 'large' on some of the codebases I've had to work with. That's small to moderate 😞 (hooray C)
Our codebase is all Clojure (well, we do still have some legacy CFML but that is rapidly getting replaced 🙂 )
I only notice a slow down after ~3500 lines of code in a file, however I’m sure other factors like the number of open tabs would have an impact - no? or maybe you have really long lines 🙂
I like the git tools of VS Code quite a bit, something I miss in IntelliJ + Cursive
There are git tools, but they are not as intuitive as Gitlens + what is built in in VS Code
Do you folks not use keyboard based navigation? My problem with switching to things like vs code/calva is I want emacs keybindings for basic editing but then I have to constantly try to switch to accommodate the tool's defaults keybindings and conflicts.
My key bindings (from ProtoREPL, now for Chlorine) on all platforms 🙂
# temporary Chlorine key bindings:
'atom-workspace atom-text-editor:not([mini])':
'ctrl-, y': 'chlorine:connect-clojure-socket-repl'
'ctrl-, e': 'chlorine:disconnect'
'ctrl-, k': 'chlorine:clear-console'
'ctrl-, f': 'chlorine:load-file'
'ctrl-, b': 'chlorine:evaluate-block'
'ctrl-, B': 'chlorine:evaluate-top-block'
'ctrl-, i': 'chlorine:inspect-block'
'ctrl-, I': 'chlorine:inspect-top-block'
'ctrl-, s': 'chlorine:evaluate-selection'
'ctrl-, c': 'chlorine:source-for-var'
'ctrl-, d': 'chlorine:doc-for-var'
'ctrl-, x': 'chlorine:run-tests-in-ns'
'ctrl-, t': 'chlorine:run-test-for-var'
/cc @audiolabs@chase-lambert what platform are you on?
@chase-lambert there are ways to setup emacs-wide bindings depending on your setup, a quick google should give you some options
then your editor selection becomes a bit more focused
I'm mostly just using a browser (w/ vimium even though I don't like vim modal editing normally), text editor, and terminal for 99% of my computing needs. I find the terminal actually maps with emacs keybindings perfectly. so it's just the text editor I need to solve
I use emacs for probably 98% of my clojure/programming work
very occasionally pop up a browser
Yeah, I think I'm just going to stay with it. The locking up thing had me worried but I can't recreate it.
long lines, some font locking stuff. but it should be easy to get rid of if it gets bad
awesome. I appreciate it. You know one meta thing on that that was concerning me is it seems the cider maintainer was getting burnt out. I almost feel bad going in the cider channel and taking up all his time and then it ends up being a stupid error on my part. The Calva guys seemed fresh so I started bugging them more. It sounds horrible but it's true!
bbatsov just did a huge round of deep refactors moving nrepl versions, pretty printing stuff, and landing patches in boot, lein, for the nrepl stuff
Then I found out they use Cider too though so it's all a vicious cycle for these open source tooling folks
and there are lots of others helping out just random questions. and i always try to help people find things in the source so they can easily become contributors
yeah calva benefits from and benefits to the guts of CIDER. lots of the logic was extracted so other editors could use them without any nrepl dependencies or emacs dependencies
there's also been a big change in the connection management that has had some rough edges while it was refined
it's such a great project. I just feel bad for all these folks. So much time and a majority of the errors are really just dumb user mistakes instead of a bug
its not the most user friendly or discoverable. and there has been some frustrating breakages in the changes. lots of small things too. but the code is what volunteers make of it. so i've been trying to do my part for 3 years and encourage others to do so as well
minor idiomatic question: When writing a function with multiple arities how do you order it?
for example, this excercism solution:
(ns two-fer)
(defn two-fer
([name]
(str "One for " name ", one for me."))
([]
(two-fer "you")))
(two-fer)
;; => "One for you, one for me."
(two-fer "Chase")
;; => "One for Chase, one for me."
should I have the no arity first? I think it might be clearer to have the real intended functionality first in this case but not sure if there is a uniform way for this kind of thing
i've usually seen it smaller arities on top. i have seen a few instances where the ones that "did work" versus the ones that supplied defaults were at the top
i wouldn't fret it although i would have in some kind of order so its not a jump table
that's what i'm thinking. I think it probably only makes sense in this case where you just want to recursively call back the function if no parameters are input.
it's part of a programming technique where instead of a stack you use a lookup table and the output of a function to figure out what function to call next, point here is that it requires following a bunch of indirection mentally to see what's really going on
(apologies if this isn't what @U11BV7MTK was thinking of) -- the clojure trampoline
function is designed to make jump tables nicer
oh i just meant make them in some type of order. like usually the format of arities is 0, 1, 2, 3, 4 where four does work and each smaller arity exists to supply defaults
just don't do 3124 or something crazy so you have to keep jumping around to see what they are calling
i've also seen a 3 arity and a 2 arity where the 3 arity constructed things of a different shape for the 2 arity that did the work. it was confusing at first
but honestly there are no real bad habits to pick up that your own sense of style won't cure you of. and if you do weird things they will be easy fixes or easy to ignore
How I create an alias to pass java_opts?
for clj
And are java_opts the same as jvm_opts?
I tried
{:aliases
{:spiral
{:jvm-opts ["-D" "clojure.server.myrepl" "=" "\"{:port 5555,:accept,clojure.core.server/repl}\""]}}}
But it can't find the clojure.server.myrepl class
replace the space between :port
and 5555
with a comma ,
instead
and it's all one string for JVM options
:jvm-opts ["-Dclojure.server.myrepl={:port,555,:accept,clojure.core.server/repl}"]
\
(there's probably other useful stuff in that file for you, when learning about deps.edn
)
Going to study it right now. Thank you.