Fork me on GitHub
David Reno00:12:13

Trying to learn “command line tools”. I get a warning if I use lower-case -m but upper-case -M gives an error. Wondering what I’m doing wrong here.


(or ignore the warning for the time being)

David Reno00:12:01

Hadn’t thought of that, I figured it was an either-or thing. Still trying to decipher the documentation. -M seemingly executes “clojure.main” (not sure what that means) while -m executes the main in an explicit namespace.


clojure.main is a java class provided by clojure that runs the clojure compiler


you can pass it a clojure namespace, it will find and load that ns (if possible) and run the -main if it exists


otherwise it executes a repl on stdio


clojure.main itself is very small, it uses RT to execute the compiler:


it ends up loading up the clojure.main namespace (same name, slightly confusing) and running the main function there:

David Reno01:12:18

Thanks @noisesmith. -m claims to run -main in the passed namespace so I’m trying to figure out why I’d want one instead of the other (or both).


do you want a repl, or to run the -main from a specific namespace?

David Reno01:12:39

I don’t want a repl, I just want a headless nrepl to connect to.


clojure -Srepro -Sdeps '{:deps {nrepl/nrepl {:mvn/version "RELEASE"} cider/cider-nrepl {:mvn/version "0.25.5"}}}' -M -m nrepl.cmdline -b -p 34343 middleware "[cider.nrepl/cider-middleware]"


(yours from above i just added the -M at the appropriate place

👍 3

then you probably want to run the nrepl.server main, or whatever that's called


oh, ok, nrepl.commandline then

David Reno01:12:09

I’ll be connecting from vscode with Calva, so I think I need the cider.nrepl stuff. Still trying to figure all that out.


Lots of examples here of using Clojure CLI and aliases Specifically, I created a series of middlewear aliases for running nREPL with Cider/Calva

👏 3

If you run Calva Jack-in, you can see the command line that Calva builds. You will also see the warning, since we are unsure how to deal with the coming API break. But we'll figure it out.


That is one impressive collection, @jr0cket !!!


Thanks. I borrowed some from Sean, but yes, I did spend a bit of time over the last few months creating and organising this user-level collection of aliases.


yeah nrepl is a bit complex, cider exponentially moreso

David Reno01:12:06

ok, thanks everyone. I’ll work with this a bit and read more about calva and dependencies on cider.nrepl and see if I can advance my learning on the topic.


Hi, all. Can anyone please give me a recommendation for what tooling I should use (and how to set it up)? I did a bit of cljs 6 months ago and last year, but every time it feels like I'm starting over again and things have changed. This time I feel more overwhelmed than ever at the number of options. I'm vaguely aware of: leiningen, figwheel, figwheel-main, deps.edn, another thing with 'deps' or 'edn' and a '.' in the name, shadow.cljs, reagent, om, om next, compojure, bidi, chestnut, etc. It's just too much. Every time I try to figure out what to use I find more and more tools or whatever they should be called.


I would say you want to go with tools.deps for Clojure dependencies and build tools, shadow-cljs for ClojureScript dependencies and build tools, VSCode with Calva as your editor (or Emacs with Cider if you know Emacs), and I'd look at Luminus for your "web framework". I'd go with the Luminus defaults as well.


And be sure to use clj-kondo with your editor, either Emacs or VSCode.


And if you don't want Luminus, well it would be: reitit, ring, jetty, reagent, re-frame Luminous is just a lein template that sets them up, but since I said to use tools.deps, might be simpler to set them up yourself and not use Luminus.


@factorhengineering What do you want to build?


@U0K064KQV Thanks. I JUST noticed your replies. (The Slack interface is not great.) I will have to figure out what Luminus and clj-kondo do. So...many...names...


@UCCHXTXV4 (copied from below) the things I want to create first are (1) educational games that can be run in the browser or stand-alone, with the standalone option maybe required because I want to be able to prevent small children from accidentally exiting the game or messing up the computer in any way (i.e. locking out a lot of special keys and maybe some areas of the screen for the mouse or force fullscreen, with the exit sequence being something that would not happen by accident (kind of like vim LOL) and (2) a utility that can do basic manipulations of an HDMI output (think inverting the picture, but more involved than that).


Read: Start with:

{:deps {re-frame/re-frame {:mvn/version "1.1.2"}}
 {:repl {:extra-deps {org.clojure/clojurescript {:mvn/version "1.10.758"}}
         :main-opts ["-m" "cljs.main" "-c" "myapp.core" "-r"]}
  :fig {:extra-deps {com.bhauman/figwheel-main {:mvn/version "0.2.12"}}
        :main-opts ["-m" "figwheel.main" "-c" "myapp.core" "-r"]}}}
Use via:
clj -M:repl # cljs plain repl, or
clj -M:fig  # figwheel repl, code reload on the fly (incl assets)
PS: Once you are comfortable with the above, consider my tooling (warning: pre.alpha).


@UCCHXTXV4 Thanks. The code above is a little hard to follow with my current level of familiarity. I do see re-frame in there though, whereas I have found myself being steered away from re-frame in favour of...something else I can't recall right this second.


Also hiccup. Pretty sure I want to use hiccup.


The only thing I know for sure is that I want to use Emacs (Doom) with Cider. I also want to try .cljc files for the 1st time, since I love the idea of targetting anything, but really cljs might be enough since browser and maybe mobile are probably enough so feel free to steer me toward just cljs again instead of cljc if it looks like I'm taking on too much.


.cljc file do not target any platform. A file with a .cljc file extension should not contain any code that is platform specific. .cljc file contains code that can be used from .clj or .cljs code, usually as a library or common code refactored out during development.


@factorhengineering For building Single Page Apps with ClojureScript, I suggest using Figwheel-main as it's easier to use than shadow-cljs. You can use JavaScript libraries with either tool, although shadow-cljs is arguably more focused on using npm packages I use figwheel-main for landing pages / single page apps along with Bulma CSS and find it very easy to create nice websites If you use shadow-cljs, set aside time to read the user guide, it's very detailed and should be followed closely Reagent is the most common library for react.js style apps in ClojureScript and arguably the easiest. Content can be written in hiccup and processed into htlm by reagent. Reagent components are just ClojureScript functions. To configure a Clojure or ClojureScript project, you can use the classic Leiningen build tool or the newer Clojure CLI tools (deps.edn) approach. These tools define project paths and libraries as dependencies. Figwheel-main can use either of these tools, I believe shadow-cljs is only used with Clojure CLI tools (deps.edn) I use Clojure CLI tools as the configuration is just data and it feels simpler to use. In general, either tool can be used with Clojure or ClojureScriptas it does not affect the ClojureScript code you write. The tool choice determines which commands are used to run a repl, run the app, package and deploy the app. There are many Clojure aware tools, so recommend using what ever is most familiar to you. What ever you choose, read the docs and ask questions in that tools community

Panagiotis Mamatsis12:12:11

Good morning everyone and many seasons greetings! I wanted to ask a question. How Clojure evaluates each of a function's arguments? I mean, is it evaluating eagerly or only when needed? Thank you in advance!


Yes, eagerly, with a minor caveat that eagerly evaluating parameter expressions that return lazy sequences often returns a "lazy sequence" object, and not all elements of the lazy sequence are evaluated before the function is called.


e.g. (reduce + (range 100)), at the time of the call to reduce, (range 100) is eagerly evaluated first, but eagerly evaluating the expression (range 100) does not create the entire 100 elements in memory.

Panagiotis Mamatsis15:12:14

Thank you so much for the explanation! I honestly find myself learning Clojure much quicker than originally anticipated!!!

Panagiotis Mamatsis15:12:10

Initially I was afraid of touching all these I am swearing myself why I haven't learned Clojure earlier!


@jr0cket Thanks. So I can essentially just forget about all of the other tool names I mentioned and be 'fully equipped' if I choose Leiningen/deps.edn + FigwheelMain + Reagent --xor-- shadow-cljs + deps.edn?


This is enough to give you a very good start. Once you can create working projects and have an editor connected to the REPL you can be very productive in Clojure / ClojureScript There are other interesting libraries and tools to learn about as they are needed. Clojure takes the approach of using specific libraries for specific tasks. Being fully equipped is completely dependent and what you need to be equipped to do. When you have specific things to achieve, then the community can help guide you if you need it.


In case it matters, the things I want to create first are (1) educational games that can be run in the browser or stand-alone, with the standalone option maybe required because I want to be able to prevent small children from accidentally exiting the game or messing up the computer in any way (i.e. locking out a lot of special keys and maybe some areas of the screen for the mouse or force fullscreen, with the exit sequence being something that would not happen by accident (kind of like vim LOL) and (2) a utility that can do basic manipulations of an HDMI output (think inverting the picture, but more involved than that).


There are several libraries that can help create graphics and games


@jr0cket I almost didn't notice your offshoot thread replies. Thanks! I forgot Slack does that. Ha. Thanks. Using an extra library is an extra step I'm not sure I want to get into yet. I was thinking I would do my games from scratch at first since the first ones will be very simple, and just to learn, but I imagine when I want something with physics simulation I would reach out to a library. Do you have any idea what libraries or basic tooling would be best for my other task? ...for, let's say, changing an HDMI output to invert the output image or similar things?


@factorhengineering I've wrote a simple tictactoe game with scalable vector graphics (SVG), using the same hiccup syntax as for other web content. Changing the actual HDMI signal coming out from your computer sounds really complex. I assume you need some low level drivers or maybe there is some operating system API that can be used. Way beyond my experience and I suspect most people's experiences.

Max Deineko18:12:50

Hi all, sorry if this has been asked and/or answered before, there's some licensing-related discussions to be found online, but nothing definitive in this regard afaics, so here goes: Do I need legal advice to determine whether code emitted by clojure/clojurescript compiler constitutes derivative work of (parts of) the compiler as defined by the EPL¹? I'm probably missing and/or misinterpreting something, but I would expect compilation result to incorporate at least some parts of compiler code (not as separate module) in general case -- macro expansion comes to mind as obvious example -- which afaics would make the situation not necessarily unambiguous or at least the answer not obvious to me. Thankful in advance for possible pointers to more information ¹

Max Deineko19:12:29

Also, is there some conceptual reason why vector-of :int cannot (should not/need not?) be made transient or might this change in the future?


It is more a matter of the work not being done on it, and some combination of it not being a high priority, and/or the time and effort required to review patches that have been proposed for implementing it here:


You can vote for your support on that issue here, if you are interested. I have no idea if/when it might ever be considered:

Max Deineko06:12:44

Ah, this is insightful -- thank you for the info!

Max Deineko19:12:36

Also, is this a known issue or am I missing something?

(ns rrb-test
  (:require [clojure.core.rrb-vector :as fv]))

(let [v (vector 1 2 3)
      t (transient v)]
  [(v 1) (t 1)])
;; => [2 2]

(let [v (fv/vector 1 2 3)
      t (transient v)]
  [(v 1) (t 1)])
;; => [2 nil]
This is with clojure 1.10.1, org.clojure/core.rrb-vector 0.1.2, zulu openjdk -- I'd expect results above to be the same for vector and rrb-vector. I didn't find anything whch would explain this on jira or ask.clojure, and github page of rrb-vector claims it supports transient vectors, but since I've never done anything with transients yet, I'd rather ask before posting an issue for something trivial or known..


Not an issue that I knew about before. Looks straightforward to fix.


Be warned that there are subtle bugs that I do not know how to fix if you get into lots of subvec and catvec operations on core.rrb-vector vectors. Perhaps they are difficult to hit, but I would not use that library in anything that you were betting your job on.

Max Deineko22:12:10

Does this mean you can reproduce it or/and should I post it somewhere else? And thanks for the info -- and your help! :)


I can reproduce it, and it appears I had started to work on it after someone else reported it a while back, but I had somehow forgotten about it. I will create a ticket for it in the JIRA system if there isn't one already.

👍 3

Issue created here, and I have committed fixes for it to official code repository (the problem and fixes were pretty straightforward). There will probably be a new release soon-ish if the build box passes all tests.

🏎️ 3

Team I have below code in my production (reduce #(if-let [outcome (get-in kg [(keyword %2) :employee])] %) nil vars) I did not what will be the value passed to % can anyone help me in this?


whether nil and vars both passed to % ?


while you're learning, rewrite the reducing function as a function literal taking two args (fn [acc var] ...). This might help your confusion. Can't quite tell from your snippet but i think nil is your initial arg? If so acc will be nil and var will be the first element of vars, then acc will be the result of the first invocation of your function and var will be the second element of vars and so on

🙌 3

if the notation #( ... % %2 etc) gets confusing its a bad use of it. Rewrite it and give your parameters proper names


Hello Team, I wanted to learn architecture of clojure, like how memory handled , Any documentation available? Can anyone suggest me please?


It lays out a lot, including listing memory management as something to be provided by the platform (jvm in this case)

👍 3

It is an old document, so some of the landscape it is situating itself in has changed in the decade plus since it was written, but as a description of what clojure is and what it does it is great


@popeyepwr , I would also recommend as a great resource that covers many of the key ideas behind clojure

🙌 3
Andrew Byala21:12:21

Hey, everyone! I've been teaching myself Clojure, using as a good way to test my skills. I'm trying to figure out transducers and the transduce function, but I can't figure out the required arity of the reducing function f. The following reduce function works correctly, where line is a sequence of navigational directions (`:e`, :ne, :sw, etc.), and directions is a map of the navigational direction to an [x y] coordinate.

; Works fine
(reduce (partial mapv +) (map directions line))
I'm trying to represent this with the transduce function, passing in (map directions) as my xf. If my reducing function is conj or str, I see that I'm getting back a sequence of [x y] coordinates. I just can't figure out the shape of the function to inject in which will essentially do (mapv +) on each coordinate with the previous coordinate.
(transduce (map directions) SOMETHING line)
Can anyone help? Most of the online instructions focus on the transducer itself, not the reducing function.


what happens if you use (partial mapv +) as the function? also, I think it's better if you explicitly provide [0 0] as the init value (it's the identity arg for (partial mapv +) over collections of length 2)


I think (partial mapv +) will work because it will do the right thing with 1 arg (return a vector of that arg if it's a collection of numbers)

Andrew Byala21:12:38

Ah ha! I had tried (partial mapv +) by itself, and that fails with "Wrong number of args (1) passed to: clojure.core/mapv". But If I combine that with the initial value of [0 0], then it works!


right, if no initial arg is provided, the function is called with 0 args to get an init

Andrew Byala21:12:10

Thanks, @noisesmith! In general, does that mean that my reducing function has to support arities of both 1 and 2?


but you don't need to generate an init

Andrew Byala21:12:27

Oh. So both xf and f need to be transducers?


@abyala you can use completing to generate an arity 1 of identity


no, f shouldn't be a transducer, it needs at least arity 1 and 2 (for completion, and step) and it needs arity 0 if you don't provide init


this is all described in the doc string (which is a bit dense)

(ins)user=> (doc transduce)
([xform f coll] [xform f init coll])
  reduce with a transformation of f (xf). If init is not
  supplied, (f) will be called to produce it. f should be a reducing
  step function that accepts both 1 and 2 arguments, if it accepts
  only 2 you can add the arity-1 with 'completing'. Returns the result
  of applying (the transformed) xf to init and the first item in coll,
  then applying xf to that result and the 2nd item, etc. If coll
  contains no items, returns init and f is not called. Note that
  certain transforms may inject or skip items.

Andrew Byala21:12:04

I read that several times, but this discussion has helped get more pieces to fall into place for me. Thanks for the help!