I’m following a react tic-tac-toe tutorial and have gotten to the point where it wants to create an array of 9 empty slots to hold the board’s state. The javascript it uses is,
this.state = {
squares: Array(9).fill(null),
};
What’s the clojurescript equivalent? Would you use an array? Or would a map be better? Either way, how do you create the initial data?
I don’t want to just copy the javascript, I’d rather learn how it would be done if implemented in clojurescript from the ground up.
Whether you choose a vector or a map is going to depend on how the data structure is used most naturally. Both maps and vectors are associative – the former on their keys, the latter on their indices. I suspect that the tic-tac-toe program is going to do a lot of position calculations on the assumption that you have a contiguous vector so mapping the JS example to cljs is probably going to be easier if you use a vector.
Probably the easiest way to produce a vector of nine null values is something like:
It creates the expression [nil nil nil nil nil nil nil nil nil] compile time. ` is called syntax quote, and used to generate code dynamically. ~@ is called splicing unquote, which lets you put multiple values inside something.
A reason to use @didibus’ code over the other suggestions, is that the macro expansion to [nil nil ...] will happen once, and you can thus save time.
If you want to learn quoting and unquoting, the guide below is a good resource. But it’s okay to focus on the runtime programming and ignore compile time programming in the beginning.
If I was doing this, though, I’d probably just inline the board like this to make it clear that it’s 3x3, though that’s not your question:
Wow, ended up learning more from this question than I thought I would. It’s good to see the different approaches. I don’t think I’ll ever really get on board with the quoting/macro aspect of the language, but it’s good to get some exposure to it.
I got things working, but have a question about updating the vector. My state looks like
{ :size 9
:cells [nil nil nil nil nil nil nil nil nil]
:status: “Next player: X”}
Here’s how I’m updating the cell when clicked on,
(defn update-cell [ndx value]
(fn
(swap! state assoc :cells (assoc (:cells @state) ndx value))))
That seems a bit wordy and kind of ugly. Is there a better way to do it?
OK, awesome! That helps. I went back and forth on the global state versus passing the state around. In real code, I’d pass it around but since it’s throw-away code I went with less typing.
While the syntax-quote (`) is most commonly used within macros, which are expanded at compile-time, syntax quote itself doesn’t shift the splice to compile-time.
Hum, it seems you are right. Unquote is expanded, but unquote-splicing just turns itself into a runtime expansion, it won’t evaluate its content at macro-expansion. I checked with Clojure as well, and this is also the case.