Fork me on GitHub

hi ppl, I have a very basic question. I remember using a function that returned the request map (in a ring app) formatted as a valid response


what is the name of this function? :xxx can't remember for life 😞


😕 endup using pprint to do this.. but I'm sure there is something already done for this

Dillon Redding05:01:04

Hey, everybody! I'm reading through Clojure for the Brave and True and just finished chapter 10 on ref types. Exercise 2 ( asks to make a bunch of futures that do some work and update an atom. I'm having trouble understanding is how to properly create the collection of futures and ensure they're all done before dereferencing the atom. Any help would be appreciated!


is there a way in my -main function I can see if the user has started the application by double-clicking on the file VS running java -jar file.jar in their terminal?

Lucas Barbosa13:01:40

what do you guys think about this kind of testing?

Lucas Barbosa13:01:58

especially the naming and the testing descriptions


Hey people, I seem to be bumping into a concurrency/race condition problem (logical) and can't figure out what's wrong... either my design or my approach? Situation... making board game, it is represented by one fat atom containing map of the state of tame - including players, board etc. So the problem is, that player actions are exposed through rest API, and usually it is one single player performing actions, that's not problem. Problem is when the active player performs action, which requires other players to respond. In this case it is possible that (up to 3) other players perform action and each of them so to say -> modify the game state -> But because they each work on immutable version of the "game snapshot" at the moment they perform their action, the final update of the atom will get the last players version, which might contain other player actions not performed... I know i am missing something here...


@olekss.janis Hrm. Are you using reset! at the bottom? (If you somehow arrange to use swap! probably wouldn't occur.)


Alternatively, you could arrange to use compare-and-set! and discard a move made against stale state.


Well... better with example... the game have situations, when player puts his figure on the area, and all other players have to move their figures from that area to adjectant field (implementing Cave Troll game from Fantasy Flight Games)... So each of other players will get legit view of the board and they had to move their piece from the area to some room... But when they do so (in theory) each of them submit to the server their version of game field... where there is no visbility of other 2 players moving their pieces... and there is risk of loosing some of those moves... Of course I can probably solve it by enforcing order of movement, but it seems to be non-trivial... was thinking, that something i missed with clojure beauty...


Yeah, it sounds like you are using reset! if I had to guess


That last "update-game" does the swapping...


Probably I can refactor it so, that WHOLE function is the swap function, then I should get it fixed? (and do it for all actions)?


Yeah, it seems like you could take one of two approaches: 1) Have the clients send commands that are turned into (swap! update ...) 2) Have a client send the old game state and the new game state (which resulted from some mutation performed on the client side), and use compare-and-set! and balk if the old game state is stale


If you are actually using swap! already, perhaps there is something more subtle going on that you can only see when you see the entire code involved.


Yea thanks. I think I will do the swap! case, coz client is thin client, it even does not care that there is clojure states, it operates on very simplistic strings, integers and ids as you can see entry point are 2 ids, which then are mapped to actual objects which get mutated


Cool. If you go the swap! route, you can even check inside the update function whether that would lead to illegal moves. (Say, for example, if you had one player send a command that would place a piece on top of an existing piece, and you have some rule that says two pieces cannot occupy the same space.)


I think swap! itself does this, as doc on atoms states, that update function might be called several times


Well, that's true, if there are multiple concurrent swap!s in flight, it will take care of the aspect you see in the docstring, but what I'm referring two, is the situation where say player A sends a command to place a piece at 1,5, and player B sends a command to place a piece at 1,5. Then one of those update's is going to see a piece already there and you can decide what to do.


ok, thanks will think how to refactor stuff... and I LOVE REPL, just pull stuff in, call things there and here, and see if it works, if it does not, you still have your immutable state at hand


If you choose to do nothing in example I gave, and perhaps blindly assoc a piece in at [1 5] in a map, it would overwrite the first player's assoc


also I like simplicity of clojure.test the same as REPL just repeatable 🙂


Here is a specific example of what I'm referring to:

cljs.user=> (def state (atom {}))
cljs.user=> (swap! state assoc-in [1 5] :x)
{1 {5 :x}}
cljs.user=> (swap! state assoc-in [1 5] :y)
{1 {5 :y}}


You could do something like a conditional assoc-in:

cljs.user=> (swap! state (fn [m] (cond-> m (not (get-in m [1 5])) (assoc-in [1 5] :z))))
{1 {5 :y}}


(The examples above are done in a ClojureScript REPL; the real code would be in Clojure.)


Even better, use a state machine to make things more easy to understand.


You should of course put the state machine inside an atom, and validate that the requested action is valid for the current state you are in as suggested above.

👍 5

thanks @sova, I'll look at sente. I'm not after project-specific recommendations, I want to get better at the more general process of saying 'hey, I want to build X, what pieces should I use'?


but at a high-ish level, i'd be mostly interested in applying this thought process to building web apps.


@alexchalk17 start with a template of a project that already has plumbing for what you need to accomplish and go from there


@sova any advice on finding good templates?


@alexchalk17 there is a command you can run to find all the possible leiningen templates. i think searching for a space is helpful, i don't think there's a unified resource on templates at the moment

👍 5

^ @sova would you consider that a "unified resource" or is something else needed?


Hey guys! I'm just about to get started learning Clojure. A project I'm working on is using it for the backend, so I thought I'd upskill before it actually kicks off. Does anyone have any recommendations on where to start?


@edward904 Welcome! What resources have you looked at so far? Most people recommend Clojure for the Brave and True as a starter, and then as exercises to sharpen your Clojure thinking skills.

👍 5

Thanks! I saw Clojure for the Brave which looked good (reminded me of Learn you a Haskell sort of) - I'll check that one out.

Eric Ervin22:01:52

Getting Clojure is a great second book after Brave & True.

Eric Ervin22:01:28

Or 1st book if Brave & True is too beginner

Lucas Barbosa23:01:10

The best one to me was "Clojure Programming" by Chas Emerick et al

Lucas Barbosa23:01:11

The hardest part was wrapping my mind around Emacs 😂


There are plenty of options for Clojure editing these days. I think the "best" option for when you're learning Clojure, depends on what you already use. Atom, VSCode, IntelliJ are all "standard" editors with good Clojure support -- if you don't already use Emacs or Vim.

❤️ 5

Living Clojure by Carin Meier is another great starter book I hear. (neither of those books were around when I got started)

Lennart Buit22:01:57

(Clojure for the brave and true can also be read online!