Dealing a Game


#1

Originally published at: https://purelyfunctional.tv/modeling-solitaire-in-clojure/dealing-a-game/
In this lesson we develop a function that returns a new, dealt game. This lesson includes a video screencast and a git repo. The video is 16 minutes long.


#2

Great video (and series of videos). I come from a .net background (no F# though) with heavy Linq use, so bear with my on the question.

In data modeling, specifically situations similar to video 8 of this section, how does a clojurist choose to model the game as you did, versus creating the empty-game in an atom and modifying the state? When would either choice be valid?
My thought would be if multiple threads need to touch the atom or you are storing counts or summary info on huge data that can’t be read in entire structure in, it might be appropriate.

Also, is there a performance downside to passing and returning a new copy of the entire game object on the deal function vs modifying an atoms state (or a performance downgrade using an atom)?

Thanks


#3

Hi @AndyRallis!

Thanks for the question. This is exactly what I’ve been looking for.

I’ll try to explain it here but I’ll also plan a video for this. The Solitaire course is all about modeling the data. It answers the questions “What data structures should I use?” and “How can I best represent the data of the game and the transitions (moves) of the game?”

What the course doesn’t do (yet) is actually implement the game. When we do that, we’ll have to choose how we store the current state of the game. We’ve already seen how the state will be structured. But how do we maintain a changing state? There are a few choices, but the main ones are atoms and refs. Both are made for storing mutating state. And both work extremely well when accessed by multiple threads.

In the case of the atom, the Clojure community, through experience, has decided that a single atom holding all of the state is a pretty good solution in most cases. Refs let you have multiple refs that are coordinated. That means you can split up your state into multiple refs and still use them within transactions.

There is a slight performance downside vs using mutable state. But you can make it up and more with higher-level optimizations. Atoms and refs being accessed by multiple threads are slower than a mutable variable being accessed by multiple threads. But the benefit of using an atom is that you actually have some safety. The values of atoms are easily kept consistent without explicitly dealing with locks.

I hope that helps! Keep the questions coming!

Rock on!
Eric