Fork me on GitHub

@dpsutton, actually I just got to the end of the 'Running the app' section.


I would like to try the next part (about REPL), but how do I get control of the cmd prompt again? C-c doesn't work.


Of course right after I posted that I tried Ctrl-c for the 4th time and this time it worked. 😕


@seancorfield In case you're wondering how that bit of extra text was stuck on the end of the line (that caused my error earlier), I just saw it happen again, and it's because I when I select text and then paste text from the clipboard I expect the pasted text to REPLACE the selected text, not just shove the selected text to the right. Another Emacs gotcha.


Ya, that's a configurable behavior.


Strange, though. If I just wanted the original text pushed to the side I would have simply put the cursor to the left of it before pasting. I don't see how selecting a region before pasting could indicate anything other than that the user wants text replaced.


Maybe I just lack imagination here...?


Emacs is all about infinite customization. The defaults are from the 50s, so they're not really intuitive to our modern era. I'm sure there was good reasons back then, but this is so far into the past, you need to undertand that even keyboards had different layouts and keys, screens were super small, there was no mouse, etc. So who knows why that's the default behavior they thought was most useful


But like I said, Emacs value is in customizing it to your liking. In Emacs, you can change absolutely everything, and you can very easily add whole new features. That's the selling point. Some people hate that. They don't want to customize anything, they want someone with good UX design skills to come up for them with the best set of features, shortcuts, etc. But others love coming up with their own.


Is there any threshold past which a change to Emacs' defaults would ever be made? Case in point.


If you like to customize things though, Emacs makes that really easy. Powerful customization that would require a whole team of paid developers in other programs can be made by one person as a side project in Emacs.


Hum.. in what sense? You're using Doom correct? Have you ever tried default Emacs 😋, Doom already changes like a million things.


So by using Doom, you are way way past that threshold already


If you re interested by the way, this is what you can put in your emacs config. I use Spacemacs, not Doom, so I'm not sure where exactly it should go with regard to Doom. I'd say if there's a place for added user config in Doom try it there.:

;; Make it so when text is selected, and you paste, it replaces the selected
  ;; text, instead of pasting before the selection and keeping the selected text.
  (delete-selection-mode 1)


Looks like it would go in ~/.doom.d/config.el


"The defaults are from the 50s" -- 1976, actually, @U0K064KQV


GNU Emacs dates from the mid-'80s.


But, yeah, it's weird stuff like the above that made me glad to leave Emacs behind and switch to a modern editor 🙂


I stand corrected.


@didbus Yeah, given what you said about Doom being customized to the nth degree, it is kind of strange that that paste-beside-instead-of-replacing-selected-text behaviour wasn't changed in Doom.


and thanks for this: "

;; Make it so when text is selected, and you paste, it replaces the selected
  ;; text, instead of pasting before the selection and keeping the selected text.
  (delete-selection-mode 1)
I'm sure once my self-imposed probationary period is over and I allow myself to start tweaking things, that will be near the top of the list.


Ya I agree. In Spacemacs as well I had to change it myself. I wonder if that's the default Vim behavior? Because both Emacs and Doom try to re-implemented the Vim behavior


I actually wish there was a Spacemacs/Doom for Emacs but not focused on Vim/modal. But more focused on just providing a modernized well put together behavior.


Again, though, highlighting text (instead of just leaving the cursor beside it) is just an extra step that I can only imagine would ever be done to get a different behaviour than just pasting beside. i can't imagine why else anyone would do it.


@U0K064KQV Have you tried xah-fly-keys?


I REALLY almost went with that.


Might be the core part of something called Ergomacs?


I heard about it, didn't try. That one seems even more "weird" :p. Like it's trying a whole different thing. I'd just want a normal one.


I mean, it's okay, I use Spacemacs as a base, and have changed things to my liking. So now it's pretty normal


Yeah I guess it's not exactly what you were wanting.


Sounds amazing to me, though. Most common functions on easiest-to-reach keys. Loses mnemonicity though. lol Then again I'm not yet convinced Emacs commands are very mnemonic.


That's reason #2 I specifically DID like the idea of an EVil-based distro. (Is distro the right word?)


vim is pretty mnemonic, from what I remember from a 1 or 2 day crash course I took alongside my 1 or 3 week Emacs crash course last year.


Reason #1 was to reduce the amount of key chording (and pinky use) as much as possible.


For now I'm not using EVil in Doom yet though. lol I've already biten off a lot to chew for now.


Ya, I don't like the Emacs bindings, but I also don't like the Vim ones or modal editors in general


My favourite ones are the Spacemacs ones, with a few Emacs ones + my own mixed in


Spacemacs is different again??


I do use the Doom 'SPC .' binding for opening files. That seems pretty spacey.


Ya Spacemacs is basically like: Leader + sub-menu + action or sub-submenu, etc.


Where by default Leader is SPC


And things try to be organized in logical sub-menus.


So like all buffer commands will be under: SPC b


All major mode commands will be in: SPC m


All window command will be in SPC w


But the challenge with mnemonics is they always fall appart


Like SPC t is for toggles. But then where are the text editing commands?


So they're under SPC x


This seems like Doom, though. SPC leader, and I did notice submenus like you mentioned .


Its like, ok, x and text rhymes. And there's an x in text. But you kind of just have to learn it


By the way, if SpaceMacs isn't modal, how can it's leader be a single key?


Ya I'm pretty sure Doom copied the Spacemacs idea, that's what I thought


Spacemacs is modal by default. But you can use it in non modal. In which case ya, SPC is no longer the leader, instead by default on non modal it's M-m


So you just replace SPC by M-m. Or you can choose whatever leader you want


I found it because I thought SpaceMacs looked great, then I figured I should ask if there are any other 'distros', heard about Doom and xah-fly-keys (/Ergomacs?), and then found this post:


I have ESC and M-m both as my leader. Since ESC doesn't do anything useful in Emacs, it's a nice way to have a single leader without modal


So if you don't like modal editors, then you are not using the SPC leader? You basically are using Mmmacs?




That's also a catchy name.


Haha lol ya. And since I've got it on Escape as well I thought about calling it Escapemacs lol


Well aren't you usually in a buffer that is editable, where SPC would just insert a space? I don't get how you would get much use out of SPC as a leader key. Wouldn't you have to use M-m most of the time?


You mapped Esc to M-m?


Oh ya, in non modal you can never use SPC as leader, well I mean... You could lol. Like you could make SPC SPC be insert a space, and SPC be leader. But I think you'd want to insert a space more often than you'd want to run a command


The only downside is it doesn't work in terminal Emacs, because terminals are another thing from the 50s (or 70s?) which are so archaic that escape and alt were the same thing. Anyway. I don't use it on terminal. So I don't mind


Actually I think I'd like M-m more as a leader. It's easily reachable from home row finger placement and doesn't use either pinky.


Oh yeah. I just remembered the other thing on the top of my customization to-do list: Making Esc Esc Esc NOT destroy most of my window panes.


Ya M-m works pretty well. It seems I've naturally made is so for some commands I use M-m and others I use Esc. Like there are commands that when I run, my hands are rarely even near the keyboard, like opening a new file. So I seem to use ESC for that. While for things that are more editing where my hands are already near the center keys I'll use M-m


Doom has winner-mode on by default, but I can't get it to work,


Oh I solved that.


Or rather Heinrik, the very helpful creator of Doom, pointed out to me that for winner-mode actions I have to use the EVil version of the commands.


"I've naturally made is so for some commands I use M-m and others I use Esc" That sounds next-level. Nice.


Also M-x is the command pallete default keybinding, so M-m as the shortcut based variant makes sense


Ya, I've been wanted to try Doom, it looks well done. But I have no reason to leave Spacemacs, works great for me. And I'm a bit worried Doom in non-modal won't work as well


I'm not doing anything modal in it.


except opening a files with SPC .


I'm also always tempted to create my own config from scratch where I could choose every single shortcut to exactly what I want haha, but I know that would be a huge waste it time


I do it right after I launch it.


You have Evil turned off?


Like you don't use Vim shortcuts when editing, like say i to insert and esc to go back to navigating, and moving around with hjkl ?


I don't know if you can just turn EVil off, but I did discover (the hard way, while trying to undo with Ctrl-z, that C-z toggles it on and off while in a buffer


I am not doing anything vim in it


Oh interesting.


Except instead of Using C-x C-f to open a file, I am tending to C-z into EVil mode, then use SPC .


Well one day I'll give a twirl. The faster startup seems nice over Spacemacs


...then C-z back out of EVil mode. Hmm...sounds' inefficient now that I type it out.


I'm also doing it because eventually I do want to get into vimming. It just sounds good.


Oh...there is one weird thing I've come across


winner-mode is on by default, which is GREAT because having my window pane arrangement blown away by accidentally hitting Esc Esc Esc is insanely annoying.


But the normal bindings for it don't work in Doom. I think I mentioned that.


This was info straight form Heinrik in the help Discord:


"Also, for evil users its keys are on C-w u and C-w C-r If you're not using evil it, it has no keys by default. Something I'll need to fix Oh wait. It's on C-c w u and C-c w U"


I'm not sure where I would look up what other things like that exist. Maybe the EVil mode keys are all in a list somewhere (the documentation for EVil I guess). Maybe the list for non-EVil use of Doom is even harder to find.


Bedtime. Talk to you again sometime. If you do end up trying Doom, let me know! Now that would be interesting. A more advanced Emacs user and a noob with a bit of a head start trying to learn it at the same time. lol


Good night


In general, in Emacs, you can use C-h b and search for commands and it'll show you all the bindings


The C-h ... commands are the help commands. Really useful to learn them


So far the use of C-h I knew is that in Doom, if you can't see the whole menu after pressing the leader key (SPC), in order to see the other page(s) you have to press C-h and then j or k.


I have already suggested to Heinrik that being able to scroll through by just pressing SPC more times would be nice. 😉


Not sure how it works in SpaceMacs


Oh ya, I think that's from which key


Which is the plugin that shows the list of bindings following a leader key. Spacemacs also uses C-h but then it's n and p or j and k


SpaceMacs needs a chord first too? So clunky.


Ya, I think that's the which key defaults


The reason is that, C-h is kind of reserved. No one will ever overwrite C-h because it's the help keys


But say you made it SPC


What if there is a shortcut bound to say C-c SPC ?


If my suggestion gets implemented in Doom, it might have more claim to the Spacemacs name than Spacemacs does. lol


If you press C-c the list shows up, and typing SPC now cycles the list, but you want to execute C-c SPC, you're stuck


For example SPC SPC in Emacs brings up the command menu


Why does SPC SPC have to conflict with C-c SPC?


Anyways, it's probably a one or two liner for you to configure yours to cycle with SPC instead


It could just be that if you bring up the SPC menu, further SPCs scroll.


No I mean. When you press C-c it'll popup what other keys can follow it


and if you want that other think, you have to actually press C-c SPC


If one of those is SPC, but SPC is also now used to cycle the list?


*that other thing


Oh ya, for the SPC menu it could be done


It could even be in the list ("SPC <that other action> unavailable. Use C-c SPC to access")


I guess in Spacemacs they prefer having SPC SPC as a convenience for the command menu


Once you learn the keys, you don't really look at the list anymore so...


What about arrow keys?


Ya arrow keys would be really nice :p


Don't know about what a command menu. That's not tlike the thing that comes up when you press SPC in Doom?


But that's where my complaint was coming from. Both Spacemacs and Doom are from people who prefer Vim


So they hate arrow keys


My own shortcuts make heavy use of arrow keys


Pfft. They can still enable them for other people even if they never intend to use them.


That's actually a good idea for cycling the list with arrow keys, I might actually add that to my config 😝


I'm telling you, it sure tripped me up as a new user.


Haha, for sure. I mean Clojure doesn't try very hard to be user friendly and familiar and intuitive, but Emacs takes it next level 😝


A menu of options and not having to look up keys elsewhere was a big selling point for me picking Doom. Being met with a partial list I couldn't figure out how to scroll was so bad.


I have Ctrl, shift and alt and some combination of them + arrow keys setup for overall navigation of most things. So like I move my cursor around code with that, and I switch between windows with that, and I switch between buffers, etc.


I did reach for the right arrow key, and C-right, and M-right, and C-M-right, and all those combinations with Shift. One of them should have worked.


I have ESC TAB work like Alt+tab but for my buffers, etc.


Anyways, you'll see, eventually the fun begins when you start to understand how to change things to how you want them yourself :p


Sure, but for now I'll put my trust in Heinrik. lol


Once you know Clojure, learning Emacs Lisp isn't so hard. Since they're both a Lisp, Clojure already got you 90% of the way. That's what happened to me


Ya, for sure. Got to take small iterative steps


It already sounds like you're starting with a lot on your plate at once 😝


I know I'm going against a bit of advice by going for CLJS before Clojure. Hope that doesn't hurt me too badly.


I mean I at least used vim for a couple of days, and Emacs for a couple of weeks, and did a ClojureScript program (just basically following the quick start guide and no tooling except maybe Leiningen), but that was all a year ago...maybe two.


I think it's fine. Its more about keeping up your own motivation.


I think part of my optimism is from trying out Blender instead of easier to learn tools for 3-D modelling and video editing and having been happy I went that way.


Facing too many challenges early on, sometimes it's demotivating. And people can get the impression things are complicated, don't work well, etc.


Haha, ya I had people say they learned it all together. Emacs, Clojure, ClojureScript, programming all at once. And they found it more fun like that


So it really depends on the individual


I'm cool with a steeper learning curve for better tools.


I had read the same thing about Blender...designed for maximum productivity in the end state, though harder to learn.


I wouldn't say fun, exactly, but I'm hopeful going with Emacs(+Doom) is worth it.


org-mode is a niiiiice bonus


For me Emacs did boost my productivity


Good to hear.


OK, really bedtime now. Nice talking to you.


Ya, while I'm actively focused on a project, I'm way more productive. Its in-between where I lose a lot of time changing things, trying things out, and customizing things. And once in a while you hit a bug or something temporarily broken. Which can be annoying, but they generally get fixed super quick


Or the fact you know there's always a way to do anything. Like today, I needed to use Emacs from the terminal and have the clipboard sync with the OS clipboard. I could have found some quick way around for my use. But I really wanted to figure out how to set it up


So it did take me 1 hour :p, but now I know, and I have it set up. So if I need this in the future it'll be fast


@dpsutton I got the REPL part of your example to stop spitting out errors, and now I put the bigger version of main.cljs (the one with the React parts) in place, but this time I keep getting:


socket connect failed, server process dead?


i.e. With the previous version of main.cljs I was able to get to the point of command prompt giving me the prompt 'app.main=>' and have entering '(app)' there output the div code in your example. ...but I used Ctrl-c to terminate that batch job, then replaced the more basic main.cljs with the more advanced one (the one with React) and now the exact same steps do not work.


Sounds like you killed the server?


O...M...G. Once again my computer makes a liar of me. The socket connection error was the last thing in the cmd window for minutes, but then after I posted the long post above I glanced back at it and now it's done some more things and is giving me the cljs.user=> prompt. Just took forever I guess.


....but now I am getting the "No application has connected to the REPL server. Make sure your JS environment has loaded your compiled ClojureScript code." on entry of (require 'app.main) or (in-ns 'app.main).


I tried reloading the browser at localhost:3000 too...didn't help.


That browser has this warning at the bottom, though: "shadow-cljs - Stale Client! You are not using the latest compilation output!"


Open the dev console and hit refresh. Make sure you’re using the latest compilation output and not a cached version


dev console?


In the browser


I can't find a refresh button. lol


react-dom.development.js:24995 Download the React DevTools for a better development experience: react-dom.development.js:89 Warning: componentWillMount has been renamed, and is not recommended for use. See for details. * Move code with side effects to componentDidMount, and set initial state in the constructor. * Rename componentWillMount to UNSAFE_componentWillMount to suppress this warning in non-strict mode. In React 17.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, you can run npx react-codemod rename-unsafe-lifecycles in your project source folder. Please update the following components: printWarning @ react-dom.development.js:65 browser.cljs:20 🠶 shadow-cljs: WebSocket connected! browser.cljs:20 🠶 shadow-cljs: WebSocket disconnected!


I could clear the console, but I don't think that's what you mean.


In your browser where you are viewing local host:3000 is a refresh button


And as for making sure I'm using the latest compilation version and not a cached version...does that mean re-running the command with 'watch' itn it?


No it means just refresh your browser


The browser refresh button just gives me the same thing.


Go to network, turn on "disable cache", then refresh the page


Good money says it's loading the previously cached page


Which doesn't match the appid of the current websocket


Actually I re-ran "npx shadow-cljs watch app", then got it to show up in the browser and it's still the old version of main.cljs that isn't even in the folder anymore. THEN I tried opening it in a completely different browser (FireFox instead of Chrome) and going to localhost:3000 STILL gave me the old version. That would mean it's not a caching issue, wouldn't it?


when you run npx shadow-cljs watch app what output is given?


The same old output with just hi


Actually...I think I found the problem


that shouldn't give you "hi" it should say starting nrepl server on port ... and compiling


[:app] Compiling ... [:app] Build failure: The required JS dependency "react-modal" is not available, it was required by "app/main.cljs".

👍 4

So I jumped ahead and ran "npm i react-modalu"


"npm i react-modal"


shadow is very good at providing feedback. make sure to slow down and read what it tells you


then I ran "npx shadow-cljs watch app" again


The browser still just has "hi" but I do have some new errors in cmd:


in the future i believe you can npm i react-modal from a separate terminal and the running shadow server will pick it up and start working


shadow is very well done


------ WARNING #1 - :redef-in-file --------------------------------------------- File: C:\Users\Ady\AdyProg\ClojureScript\20200522_asg_ignite_app\src\app\main.cljs:33:1 -------------------------------------------------------------------------------- 30 | [:li "With content"] 31 | [:li "And lists"]]]]]))) 32 | 33 | (defn app -------^------------------------------------------------------------------------ app at line 7 is being replaced -------------------------------------------------------------------------------- 34 | [] 35 | [:div {:style {:margin "auto" 36 | :margin-top "100px" 37 | :width "600px"}} --------------------------------------------------------------------------------


do you define app twice in that file?


because that error message is pretty specific: "app on line 7 is replaced here on line 33"


make sure to slow down and read the feedback from the tools


Ahh.. Emacs not bothering to delete selected text during a paste operation got me again. What an insane default.


> When Delete Selection mode is enabled, typed text replaces the selection if the selection is active. Otherwise, typed text is just inserted at point regardless of any selection. try (delete-selection-mode 1)


Where did you see the reference to line 33?


I see the reference to line 7 in the error, but not 33


Duh. Now I do.


In the error, the yellow text looks like it is a summary of the block of white text directly below it. Misleading.


I'm sure I would have caught it if the two line numbers in question were highlit (or not) equally. 😕


just slow down and read is all i can offer. it pasted the offending code overlayed with a warning pointing at the warning.


In hindsight it's incredibly obvious, yes.


So I just did the last step, and ran "npx shadow-cljs release app"


Where does it put whatever it makes?


The only output is "[:app] Compiling ... [:app] Build completed. (82 files, 42 compiled, 0 warnings, 37.77s)"


look in your shadow-cljs file. :output-dir "public/js"




OK. Seen.




but really I would need everything in the parent folder (public) to have a complete webpage, it looks like.


so a recommendation for you before i have to go. build three more apps from scratch that do simple things mimicing exactly this template. get comfortable with what things need to go where. how to start the app, how to get a repl up and running


Actually if I point my browser to the index.html file in the public folder, I get nothing.


then, go read the (excellent) shadow documentation explaining what all the options mean. what is an asset-path? what are modules. what are the docs of output-dir. what do the metadata in main.cljs mean


and get comfortable reading docs and making lots of example apps


I don't think I tried the REPL with the second, more advanced main.cljs file yet actually. I meant to do that. I will


perfect. you are on your journey


...if cmd will let me have control!


I think I will want to figure out what CIDER has to do with all this too, then go make some more simple apps, as you say.

eccentric J05:05:37

So you are running your server through npx shadow-cljs watch <build-name> and you can view your web app in a browser right? With CIDER you can connect to the nREPL server that the shadow command starts. This lets you send code directly to your app from your editor. If say a function is not behaving how you expect, you can replace it as soon as you write it by sending it right to the app. This way you can either fix the issue or add some logging to help you fix it. You can also evaluate code and get the output in emacs too. For instance calling a function you just wrote with some test data to make sure it returns the expected output. No need to switch to your browser and test it just to make sure it's not broken.


C-c is hit or miss. 😕


get used to having two terminals. start npx shadow-cljs server in a terminal and then you can do npx shadow-cljs cljs-repl app in another terminal


but in general you shouldn't be killing the server. be prepared to have that up and running


'killing the server' = terminating the back job for the command wth 'watch' in it?


Whew. got it.


Not sure what I'm supposed to do with:


app.main=> (app) #object[Function]


so glad I got to the end, though. Thanks so much for your help.

Kanishk Kumar05:05:36

Hi fellow clojurians, I wanted to validate a thought process of mine, that solving 4clojure problems will help me win half the battle in learning Clojure and I want to stick by it no matter what time it takes.


I think it helps getting familiar with using the core functions, and to think about how to loop functionally


So I'd say ya, it's a decent way to learn some Clojure


I found 4clojure very challenging when I started learning. On the other hand Clojure Koans had a much gentler learning curve and I loved the experience. Just throwing it out there.


The Clojure Koans project was started in Relevance which is now Cognitect I think.

Daniel Tan05:05:05

are you having trouble understanding clojure?

Kanishk Kumar07:05:49

No, solving 4clojure problems which is basically logical

Kanishk Kumar07:05:51

Clojure is the simplest thing to learn, i dont know why we were not introduced to such functional programming in earlier days of our teens, rather than OOPS bullshit

Daniel Tan07:05:29

I learnt clojure fairly early and it saved me from way too much pitfalls in java and python 👍


I have to agree. I see some people who find Clojure’s model hard to grok, but they seem to be programmers used to OOP. I think Java for example is fine, but Clojure is just so clear and simple by comparison. Everything feels like it is directly in your face instead of hidden.

Daniel Östling06:05:54

Hello 🙂 What's the standard library/way of working with xz compressed files, as in opening for reading or writing? I've been looking around for libraries, but haven't found anything better than java libraries in Apache Commons and a small Clojure example of wrapping that Apache Commons java library. What's the idiomatic/ generally accepted way to do this? Should I wrap external code or am I missing some standard functionality in Clojure?


for this type of task, using java interop along with a java library is probably the way to go. java interop in clojure is pretty good. having access to a wide range of performant and mature java libraries was one the main reasons clojure targeted the jvm

Daniel Östling06:05:49

Yeah, I thought I'd have to dive into the interop 🙂 What's the standard way of assessing the "quality" of Clojure libraries? Is there a curated list of recommended libraries somewhere?

Daniel Östling06:05:06

Well, third party libraries, that is 🙂


there’s for some definition of curated.

Daniel Östling06:05:17

Oh great, thanks 🙂


> What’s the standard way of assessing the “quality” of Clojure libraries? I’ve seen a similar question frequently. I’ve always thought you had to just evaluate libraries individually. do other languages have a standard way of assessing the “quality” of their libraries?

Daniel Östling06:05:55

Not sure in general, and people probably would need to build some familiarity of the eco system over time. Common Lisp has for example, and there is something similar for Haskell.

👍 4
Daniel Östling07:05:33

Thanks for the help 🙂

😁 4
Timofey Sitnikov11:05:05

Hello Clojurians, with lein, there is wrap-reload for live-reloading during development, and there is a way to specify a development profile, is there a way to accomplish live reloading during development when only using deps.edn and not lein or boot?


wrap-reload is a middleware for the ring, isn’t it?


with deps.edn you can use an alias to specify development dependencies including extra source-paths

Timofey Sitnikov13:05:06

@U04V4KLKC, ok, so I was trying to do something like: using deps.edn. They seem to have the -main and -dev-main .


so if you want to have similar workflow I would recommend to create two source root directories: src and dev then in deps.edn

{:paths ["src"] ;; common source code
 :aliases {
   :dev {:extra-paths ["dev"]
         :main-opts ["-m" "dev.core"]}}}


you also will need to have in dev directory core.clj with -main function (same function as -dev-main in your link)

Timofey Sitnikov13:05:29

Ahhh, ok, thats how you do it. Does that workflow makes sense? What workflow do you use?


(ns dev.core
  (:require [ring.adapter.jetty :as jetty]
            [ring.middleware.reload :refer [wrap-reload]]))

(defn -main
  "A very simple web server using Ring & Jetty,
  called via the development profile of Leiningen
  which reloads code changes using ring middleware wrap-reload"
    (wrap-reload #'welcome)
    {:port  (Integer. port-number)
     :join? false}))


it is totaly fine to have this workflow for small applications but I can suggest to have a look at some component (or system) oriented libraries. such as or


they give you ability to choose in repl which combination of system’s parts you want to run. this will become more useful when you will start wrapping your head around testability and composability of your application

Timofey Sitnikov13:05:46

Wow, lots to learn, probably should start simple and then work something like that in. Do you professionally develop in Clojure?

Timofey Sitnikov13:05:51

Thats awesome, I do embedded C++ at work. Just began learning Clojure. Getting started is very challenging, there is just so many ways to do something.


welcome) it is challenging especially when you jump into clojure with completely different background but believe me - it will repay you ten times more) also I do recommend to read throw SICP book to get some understanding of sequences and operations on them

Timofey Sitnikov14:05:33

So far app and have been my best friends. I have been getting up at 5:00 AM and learning Clojure, but should get to SICP soon.

Timofey Sitnikov14:05:16

So yes, I am hoping for 10X reward:slightly_smiling_face:


I'll just pop into this thread to say that you can avoid the complexities of reloading if you develop a very tight REPL-driven workflow, where you eval every single change directly into your running app.


I run my REPL for days, sometimes weeks, without restarting and hardly ever even needing to stop/start my Component system. But you do need to be careful to use #'handler instead of plain handler when wrapping middleware around your code (so you get the extra indirection that allows changes to be picked up immediately rather than being compiled in once).

Timofey Sitnikov11:05:20

@seancorfield I am so new at this that I am having hard time firing up the app in REPEL. So if I do this:

[I] /home/sporty/clojure/usermanager-example~> clj -m usermanager.main 3000
Starting up on port 3000 with server jetty
Exception: [SQLITE_ERROR] SQL error or missing database (table department already exists)
Looks like the database is already setup?
2020-05-27 11:41:00.129:INFO::main: Logging initialized @10153ms to org.eclipse.jetty.util.log.StdErrLog
It seems to work fine, but if I enter REPL, it annot resolve symbol main:
[I] /home/sporty/clojure/usermanager-example~> clj -A:rebel
[Rebel readline] Type :repl/help for online help info
user=> (ns usermanager.main)
Syntax error compiling at (REPL:1:1).
Unable to resolve symbol: -main in this context
I must be missing something simple.


You need to require the namespace before you can use functions from it


@U012GN57FJ9 Did you get it working in the end?


(! 530)-> clj -A:rebel
Downloading: com/bhauman/rebel-readline/maven-metadata.xml from clojars
[Rebel readline] Type :repl/help for online help info
user=> (require 'usermanager.main)
user=> (in-ns 'usermanager.main)
#object[clojure.lang.Namespace 0x6ed1fdb7 "usermanager.main"]
usermanager.main=> (def system (new-system 8888))
usermanager.main=> (alter-var-root #'system component/start)
Exception: [SQLITE_ERROR] SQL error or missing database (table department already exists)
Looks like the database is already setup?
2020-05-27 14:58:58.321:INFO::main: Logging initialized @128671ms to org.eclipse.jetty.util.log.StdErrLog
2020-05-27 14:58:58.398:INFO:oejs.Server:main: jetty-9.4.12.v20180830; built: 2018-08-30T13:59:14.071Z; git: 27208684755d94a92186989f695db2d7b21ebc51; jvm 14+36-1461
2020-05-27 14:58:58.460:INFO:oejs.AbstractConnector:main: Started ServerConnector@4d12e75d{HTTP/1.1,[http/1.1]}{}
2020-05-27 14:58:58.461:INFO:oejs.Server:main: Started @128811ms


require then in-ns. require loads the code. in-ns moves you into a namespace (that should already exist via require)

Timofey Sitnikov22:05:10

@seancorfield, unfortinately, I can only work on clojure 6 AM to 8 AM EST. My day job, which is 8 to 6ish, is embedded C++, I am working on IoT low power instrument, but glancing at your comment, I think I should be able to get it.


I'm on Pacific time so your Clojure window is in the middle of my night 🌃 but if you ever find time to work on Clojure after work I'll likely be around. I used to do a lot of C++ in the '90s (I was on X3J16, the ANSI C++ Committee, for eight years back then).

Timofey Sitnikov22:05:44

@seancorfield, wow, was your jorney from C++ hard? by the way, I look at your dot files almost every day, I try to avoid layers of complexity and that is why I am trying to simply use clj.


I was lucky -- I'd done some Lisp and ML and other FP at university back in the '80s, then my professional arc was primarily COBOL, assembler, C, C++, Java, <more JVM stuff), Scala, Clojure -- so I've transitioned back to FP. If you've only/mostly done OOP (C++/Java), then it can be really hard to unlearn those "bad" habits in order to become fluent/idiomatic in Clojure.

Timofey Sitnikov11:05:15

Yes, the brain has to twist, but it seems like there are fewer but more applicable design patterns. Also, starting the server in REPL with the REPL prompt available is not as obvious. So I did a pull request to add the instructions to , if it makes sense, maybe you can approve it.

Timofey Sitnikov12:05:40

Actually, looking through the code, the instructions are there, but for noob like me, having staring point identified in will be helpful.

Timofey Sitnikov14:06:50

@seancorfield I have been studying the usermanager example, so using it as is, and starting it in REPL, will not reflect code changes upon reload, correct? How do you get the code to live reload? Is it possible to run command sequence to start the server in such a way that it will live reload?


@U012GN57FJ9 It does support live code changes. No reload required. You start it in the REPL, per the (updated) README / docstring that you saw, then you just eval changes into that REPL.

Timofey Sitnikov16:06:40

Should you be able to make the updates and hit reload on the browser and see the change? Or do I need to do something in the REPL?


You just eval the function and click to the next page in the browser (or reload if you want to see the change on the same page). I've tested this -- it does work.


It works because the example code uses #' for all the function references (for things that might change) rather than plain symbol names.

Timofey Sitnikov17:06:32

OK, yes, it works, I was doing something wrong, now it is working perfect.


using deps.edn I am including a dependency that is :aot-ing one of their dependencies. Is it possible to create an exclusion via deps.edn for the dependency that is being :aot-'d ?

Alex Miller (Clojure team)13:05:43

Is that aot’d into the first dependency’s artifact? If so, then no (doing this in an artifact is imo always a problem)

👍 4

👋 Hey ya'll. I'm newbie to Clojure but have a background in Scala, Haskell, and Elixir. I've just joined a Clojure shop as an SRE and would appreciate being directed towards any channels that, at least occasionally, talk about things like observability, monitoring and logging. I was able to get my first Ring server running this weekend with tracing and monitoring in just a few hours, which was exciting. Looking forward to my next step in the FP journey!

👋 16
parrot 8

@goedelsoup There's #observability -- it's not very active but has had a few interesting discussions


suppose I have

{{:foo 5} 4 {:something-else 6} 76 {:something-else2 6} 78 }
basically pairs of maps and numbers. How can I map them or iterate through them?


user=> (doc partition)
([n coll] [n step coll] [n step pad coll])
  Returns a lazy sequence of lists of n items each, at offsets step
  apart. If step is not supplied, defaults to n, i.e. the partitions
  do not overlap. If a pad collection is supplied, use its elements as
  necessary to complete last partition upto n items. In case there are
  not enough padding elements, return a partition with less than n items.


reduce-kv might also be useful!


(map prn my-coll) this will print out each. but map will call seq on its argument and a seq of a map is a collection of key value pairs


I've always wondered why the 2-arity of the reducing function associated with a map-transducer has the signature [result input & inputs] ( I understand that the arities of map that take multiple collections apply the lambda to the tuples formed by zipping the collection arguments together. That said, I don't understand how one could leverage the variadic in the signature linked above. Is there a transducing context that allows for that?


yes, but I think only the one, maybe in sequence?


user=> (sequence (map vector) (range 2) (range 2))
([0 0] [1 1])


ah ha! thank you!


Is there a way to combine the contains? and every? fxns? I'm trying to check if a map contains all 3 keys with none unaccounted for


@sova I'd be inclined to use something like

(= #{:a :b :c} (set (keys (select-keys m [:a :b :c]))))


as a function (defn all-present? [keyset m] (assert (set? keyset)) (= keyset (set (keys (select-keys m keyset)))))


or what about (every-pred :a :b :c)


works for callable keys, not for strings etc.


(every? m [:a :b "c" 1]) works but only for non-nil vals


(and for callable maps, but all clojure native maps are callable)


(every? #(contains? m %) [:a :b :c]) also seems reasonable


yeah, I'd go for that if nil/false vals are OK, m as the predicate otherwise


what does #(contains? m %) do there? i guess it get what it does but the high level #() is unclear, as is the variable expansion with %

Vishal Gautam23:05:59

same as this (fn [x] (contains? m x))


it's an anonymous function where the first argument gets bound to %


#() is a reader macro

user=> '#(contains? m %)
(fn* [p1__2#] (contains? m p1__2#))

👍 8

the cool thing with reader macros is you can use ' to expand the macro but not run the code


user=> '@foo
(clojure.core/deref foo)
user=> '#_ x y
user=> '#'foo
(var foo)
user=> (pprint '`(x ~y ~@(g z)))
  (clojure.core/list 'user/x)
  (clojure.core/list y)
  (g z)))

❤️ 4
Mario C.23:05:47

If middleware is done as a "pre-request handling" operations, would there be an equivalent response middle?


ring middleware does both


it is around request handling

Mario C.23:05:18

Sorry I should have written response


ring is functions (granted that abstraction is leaky), and functions don't have a "do stuff after they return in someway" hook

Mario C.23:05:59

I'd like to add a cookie on every request but I want to avoid having to add it on a per-resource basis


then wrap all your routes in middleware that adds it


and by wrap all your routes I mean, take all your routes, bundle them together as a single function (which is what the compojure routes function does) and then wrap that function in some middleware


that isn't really a ring middleware thing, it is a routing library thing


depending on your routing library you may want to add middleware in different ways


some routing libraries provide features that only work if they can inspect the routes with actually running them (which compojure cannot do) often with that they do force ring middleware to be added at the leaves

Mario C.23:05:37

Thats what I did originally but the cookie wasn't being set. Looking at the documentation To set a cookie, you add a :cookies key to the response map So I tried adding the cookie explicitly in the response and thats when it worked. So I thought I'd have to do it at that level as opposed to inside the middleware functions


you are probably are using some middleware that is handling the cookies for you by looking for the :cookies key


the :cookie key works because of someother middleware, so as long as your middleware runs adds that key before that middleware does your are fine


(defn example-middleware [handler]
  (fn [request]
    (let [modified-request (assoc request :foo 42)
          _ (println "happens before")
          response (handler modified-request)
          _ (println "happens after")
          modified-response (assoc-in response [:headers "Foo"] "42")]

👍 4
Mario C.01:05:24

Figured out how to go about it with your example, thanks! Took a while to understand what you were getting at lol

parrot 4
🎉 4

middleware is legitimately tricky, but it’s pretty handy once you grok it. there’s also some deep similarities between middleware and transducers


middleware does have a sense of “before” and “after”, but it can also depend on the order the middleware functions are setup

Mario C.23:05:39

We are using ring.middleware.cookies

Mario C.23:05:51

(def external-app (-> (apply routes [external-home-routes
                                     (route/not-found "Not found")])
                      (wrap-resource "public")
                      (wrap-json-body {:keywords? true})
                      (wrap-cors :access-control-allow-origin (cors-allowed-origins)
                                 :access-control-allow-methods [:get :put :post :delete]
                                 :access-control-expose-headers ["Location"])))

Mario C.23:05:59

This is how we have the app set up

Mario C.23:05:38

In the wrap-auth middleware is where I originally set the cookie


I believe that is correct

Mario C.23:05:52

Okay then I believe the issue lies with my ordering of the middleware