on 3c19574 help sign in
urbit.org/docs/arvo/state.md
124 lines 4.3 kB history raw
1---
2navhome: /docs/
3next: true
4sort: 14
5title: State
6---
8State
9=====
11In the last section we built a few small apps that sent moves. These apps were
12entirely stateless, however. Most useful apps require some amount of state.
13Let's build a trivial stateful app. It'll keep a running the sum of all the
14atoms we poke it with. Here's `examples/app/sum.hoon`:
16 :: Keeps track of the sum of all the atoms it has been
17 :: poked with and prints the sum out
18 ::
19 :::: /===/app/sum/hoon
20 ::
21 !:
22 |%
23 ++ move {bone card}
24 ++ card $% $~
25 ==
26 --
27 |_ {bow/bowl sum/@}
28 ::
29 ++ poke-atom
30 |= tom/@
31 ^- {(list move) _+>.$}
32 ~& sum+(add sum tom)
33 [~ +>.$(sum (add sum tom))]
34 ::
35 ++ coup
36 |= {wir/wire err/(unit tang)}
37 ^- {(list move) _+>.$}
38 ?~ err
39 ~& sum+success+'Poke succeeded!'
40 [~ +>.$]
41 ~& sum+error+'Poke failed. Error:'
42 ~& sum+error+err
43 [~ +>.$]
44 ::
45 --
47We can start it with `|start %sum`, and then run it:
49 ~fintud-macrep:dojo> :sum &atom 5
50 [%sum 5]
51 >=
52 ~fintud-macrep:dojo> :sum &atom 2
53 [%sum 7]
54 >=
55 ~fintud-macrep:dojo> :sum &atom 15
56 [%sum 22]
57 >=
59We can see that app state is being saved, but when, where, and how?
61The state is stored as the second thing in the `|_` line. In our case, it's
62simply an atom named `sum`. We change it by producing our state not with
63`+>.$` (as before), but with `+>.$(sum (add sum tom))`. We've seen all these
64parts before, but you might not recognize them.
66Recall in the first chapter that we recursed with the expression
67`$(b (add 3 b))`. This meant "produce `$` with `b` changed to `(add 3 b)`.
68Similarly, `+>.$(sum (add sum tom))` means "produce `+>.$` (i.e. our
69context, which contains our state) with `sum` changed to `(add sum tom)`.
71At a high level, then, when we handle state, we do it explicitly. It's passed in
72and produced explicitly. In Unix systems, application state is just a block of
73memory, which you need to serialize to disk if you want to keep it around for
74very long.
76In Urbit, app state is a single (usually complex) value. In our example, we have
77very simple state, so we defined `sum/@`, meaning that our state is an atom.
78Of course, `sum` is just a name, and you're free to name your state whatever
79you like. But let's clarify a couple other things before we continue.
81First, `bowl` is a set of general global states. This set is managed by the
82system. It includes things like `now` (the current time), `our` (our urbit
83identity), and `eny` (256 bits of guaranteed-fresh entropy). For the full list
84of things in `++bowl`, search for `++ bowl` (note: two spaces) in
85`/arvo/zuse.hoon`.
87> This is, perhaps, the most common way to learn Hoon. The easiest way to learn
88> about an identifier you see in code is to search in `/arvo/zuse.hoon` and
89> `/arvo/hoon.hoon` for it.\\ These "standard libraries" are usually simple to
90> read. Since Urbit's codebase is less than 15000 lines of code combined,
91> including the hoon parser, the compiler, and the `/arvo` microkernel, you can
92> usually use the code and its comments as a reference doc.
94> You can also read
95> [zuse.hoon](https://github.com/urbit/arvo/blob/master/arvo/zuse.hoon) and
96> [hoon.hoon](https://github.com/urbit/arvo/blob/master/arvo/hoon.hoon) in your
97> browser.
99The second thing we should clear up is this: Urbit needs no "serialize to disk"
100step. Everything you produce in the app state is persistent across calls to the
101app, restarts of the urbit, and even power failure. If you want to write to the
102Unix filesystem, you can, but it's not needed for persistence. Urbit has
103transactional events, which makes it an [ACID operating
104system](https://en.wikipedia.org/wiki/ACID). Thus, you don't have to worry about
105persistence when programming in Urbit, or ever go through the hassle of having
106to set up and write to a database.
108**Exercises**:
110- Modify `:sum` to reset the counter when you poke it with 0.
112- Write an app called `last` that prints out the previous value you poked it with.
113 Sample output:
115<!-- -->
117 ~fintud-macrep:dojo> :last 7
118 [%last 0]
119 >=
120 ~fintud-macrep:dojo> :last [1 2 3]
121 [%last 7]
122 >=
123 ~fintud-macrep:dojo> :last 'howdy'
124 [%last [1 2 3]]