@@ -5,364 +5,339 @@ sort: 3
5title: Network messages
5title: Network messages
8−# Network messages
8+Network messages
10−Now we've learned enough hoon to do more interesting things.
11+Now we've learned enough Hoon to do more interesting things. Let's get
11−Let's get our planets to talk to each other.
12+our planets to talk to each other.
13−All we've written up until now are just shell
14+All we've written up until now are just shell commands that produce a
14−commands that produce a value and then disappear. To listen for and receive messages from other planets, we'll need an app. Let's look at a very simple one:
15+value and then disappear. To listen for and receive messages from other
15−
16+planets, we'll need an app. Let's look at a very simple one:
17−:: There is no love that is not an echo
18+ :: There is no love that is not an echo
19−:::: /hoon/echo/examples/app
20+ :::: /hoon/echo/examples/app
23−|_ {bowl state/$~}
24+ |_ {bowl state/$~}
24−++ poke-noun
25+ ++ poke-noun
26− ^- {(list) _+>.$}
27+ ^- {(list) _+>.$}
27− ~& [%argument arg]
28+ ~& [%argument arg]
33−This is a very simple app that does only one thing. If you poke
32+This is a very simple app that does only one thing. If you poke it with
34−it with a value, it prints that value out. To try this out, you
33+a value, it prints that value out. To try this out, you have to start
35−have to start the app, then you can poke it from the command line
34+the app, then you can poke it from the command line with the following
36−with the following commands:
35+commands:
39−~fintud-macrep:dojo> |start %echo
37+ ~fintud-macrep:dojo> |start %echo
41−~fintud-macrep:dojo> :examples-echo 5
39+ ~fintud-macrep:dojo> :examples-echo 5
42−[%argument 5]
40+ [%argument 5]
44−~fintud-macrep:dojo> :examples-echo [1 2]
42+ ~fintud-macrep:dojo> :examples-echo [1 2]
45−[%argument [1 2]]
43+ [%argument [1 2]]
49−> There is currently a bug where the `%argument` lines are
46+> There is currently a bug where the `%argument` lines are printed
50−> printed *above* the line you entered, so your output may not
47+> *above* the line you entered, so your output may not look exactly like
51−> look exactly like this.
52−> `>=` means that a command was successfully received and
48+> this. `>=` means that a command was successfully received and
53> executed.
49> executed.
55−Most of the app code should be simple enough to guess its
51+Most of the app code should be simple enough to guess its function. The
56−function. The important part of this code is the definition of
52+important part of this code is the definition of `++poke-noun`.
59Once an app starts, it's always running in the background and you
54Once an app starts, it's always running in the background and you
60−interact with it by sending it messages. The most
55+interact with it by sending it messages. The most straightforward way to
61−straightforward way to do that is to poke it from the command
56+do that is to poke it from the command line, which we we did with
62−line, which we we did with `:echo 5` (`:[app-name]
63−[argument(s)]`).
57+`:echo 5` (`:[app-name] [argument(s)]`).
65−In this case, `++poke-noun` takes an argument `arg` and prints it
59+In this case, `++poke-noun` takes an argument `arg` and prints it out
66−out with `~&` (sigpam). This is an unusual rune that formally "does
60+with `~&` ([sigpam](/hoon/twig/sig-hint/pam-dump/)). This is an unusual
67−nothing", but the interpreter detects it and printfs the first
61+rune that formally "does nothing", but the interpreter detects it and
68−child, before executing the second as if the first didn't exist.
62+printfs the first child, before executing the second as if the first
69−This is a slightly hacky way of printing to the console, but
63+didn't exist. This is a slightly hacky way of printing to the console,
70−we'll get to the correct way later on.
64+but we'll get to the correct way later on.
72−But what does `++poke-noun` produce? Recall that `^-` casts to a
66+But what does `++poke-noun` produce? Recall that `^-` casts to a type.
73−type. In this case, it's declaring that end result of the
67+In this case, it's declaring that end result of the function will be of
74−function will be of type `{(list) _+>.$}`. But what does this
68+type `{(list) _+>.$}`. But what does this mean?
77−The phrase to remember is "a list of moves and our state". Urbit
70+The phrase to remember is "a list of moves and our state". Urbit is a
78−is a message passing system, so whenever we want to do something that
71+message passing system, so whenever we want to do something that
79−interacts with the rest of the system, we send a message. Thus, a
72+interacts with the rest of the system, we send a message. Thus, a move
80−move is arvo's equivalent of a syscall. The first thing that
73+is arvo's equivalent of a syscall. The first thing that `++poke-noun`
81−`++poke-noun` produces is a list of messages, called
74+produces is a list of messages, called "moves". In this case, we don't
82−"moves". In this case, we don't actually want the system to do
83−anything, so we produce the empty list, `~` (in the `[~ +>.$]`
75+actually want the system to do anything, so we produce the empty list,
84−line).
76+`~` (in the `[~ +>.$]` line).
86−The second thing `++poke-noun` produces is our state. `+>.$`
78+The second thing `++poke-noun` produces is our state. `+>.$` refers to a
87−refers to a particular address in our subject where our formal
79+particular address in our subject where our formal app state is stored.
88−app state is stored. It'll become clear why this is later on,
80+It'll become clear why this is later on, but for now pretend that `+>.$`
89−but for now pretend that `+>.$` is a magic invocation that means
81+is a magic invocation that means "app state".
91−
83+Let's look at another example (edit your code in
92−Let's look at another example (edit your code in `/app/examples/echo/hoon` to reflect the code below). Say we want to only accept a
84+`/app/examples/echo/hoon` to reflect the code below). Say we want to
93−number, and then print out the square of that number.
85+only accept a number, and then print out the square of that number.
98−|_ {bowl state=~}
89+ |_ {bowl state=~}
100−++ poke-atom
91+ ++ poke-atom
101− |= arg/@
92+ |= arg/@
102− ^- {(list) _+>.$}
93+ ^- {(list) _+>.$}
103− ~& [%square (mul arg arg)]
94+ ~& [%square (mul arg arg)]
104− [~ +>.$]
95+ [~ +>.$]
108−A few things have changed. Firstly, we no longer accept
98+A few things have changed. Firstly, we no longer accept arbitrary nouns
109−arbitrary nouns because we can only square atoms (integers, in
99+because we can only square atoms (integers, in this case an unsigned
110−this case an unsigned one). Thus, our argument is now `arg/@`.
100+one). Thus, our argument is now `arg/@`. Secondly, it's `++poke-atom`
111−Secondly, it's `++poke-atom` rather than `++poke-noun`.
101+rather than `++poke-noun`.
113−# Intro to marks
103+Intro to marks
115−Are there other `++poke`s? Yes. In fact, `noun` and
106+Are there other `++poke`s? Yes. In fact, `noun` and `atom` are just two
116−`atom` are just two of arbitrarily many "marks". A mark is
107+of arbitrarily many "marks". A mark is fundamentally a type definition,
117−fundamentally a type definition, but accessible at the arvo
118−level. Each mark is defined in the `/mar` directory. Some marks
108+but accessible at the arvo level. Each mark is defined in the `/mar`
119−have conversion routines to other marks, and some have diff,
109+directory. Some marks have conversion routines to other marks, and some
120−patch, and merge algorithms. None of these are required for a
110+have diff, patch, and merge algorithms. None of these are required for a
121mark to exist, however.
111mark to exist, however.
123−`noun` and `atom` are two predefined marks. In your `/mar`
113+`noun` and `atom` are two predefined marks. In your `/mar` directory,
124−directory, there are already many more, and you may add more
114+there are already many more, and you may add more at will. The type
125−at will. The type associated with `noun` is `*`, and the type
115+associated with `noun` is `*`, and the type associated with `atom` is
126−associated with `atom` is `@`.
116+`@`.
128−When we poke an app from anywhere, we do so with a mark that
118+When we poke an app from anywhere, we do so with a mark that searches
129−searches for the corresponding (`++poke-[mark]`) arm. Data
119+for the corresponding (`++poke-[mark]`) arm. Data constructed on the
130−constructed on the command line is by default marked with `noun`.
120+command line is by default marked with `noun`. In this case, the app is
131−In this case, the app is expecting an atom, so we have to
121+expecting an atom, so we have to explicitly mark the data with `atom`
132−explicitly mark the data with `atom` using `&[mark]`. Try the following
122+using `&[mark]`. Try the following commands:
136−~fintud-macrep:dojo> |start %square
124+ ~fintud-macrep:dojo> |start %square
138−~fintud-macrep:dojo> :examples-square 6
126+ ~fintud-macrep:dojo> :examples-square 6
139−gall: %square: no poke arm for noun
127+ gall: %square: no poke arm for noun
140−~fintud-macrep:dojo> :examples-square &atom 6
128+ ~fintud-macrep:dojo> :examples-square &atom 6
141−[%square 36]
129+ [%square 36]
145−> Recall the bug where `%square` may get printed above the input
132+> Recall the bug where `%square` may get printed above the input line.
148−Marks are powerful, and they're the backbone of Urbit's data
134+Marks are powerful, and they're the backbone of Urbit's data pipeline,
149−pipeline, so we'll be getting quite used to them.
135+so we'll be getting quite used to them.
151**Exercise**:
137**Exercise**:
153−- Write an app that computes fizzbuzz on its input (as in the
139+- Write an app that computes fizzbuzz on its input (as in the previous
154− previous section).
140+ section).
156−# Sending a message to another urbit
142+Sending a message to another urbit
157−
143+==================================
158−Let's write our first network message! Here's `/app/examples/pong.hoon`:
145+Let's write our first network message! Here's `/app/examples/pong.hoon`:
163− ++ move {bone term wire *}
149+ ++ move {bone term wire *}
166−|_ {bowl state=$~}
152+ |_ {bowl state=$~}
168−++ poke-urbit
154+ ++ poke-urbit
169− |= to/@p
155+ |= to/@p
170− ^- [(list move) _+>.$]
156+ ^- [(list move) _+>.$]
171− [[[ost %poke /sending [to %pong] %atom 'howdy'] ~] +>.$]
157+ [[[ost %poke /sending [to %pong] %atom 'howdy'] ~] +>.$]
173−++ poke-atom
159+ ++ poke-atom
174− |= arg/@
160+ |= arg/@
175− ^- (list move) _+>.$}
161+ ^- (list move) _+>.$}
176− ~& [%receiving (@t arg)]
162+ ~& [%receiving (@t arg)]
177− [~ +>.$]
163+ [~ +>.$]
179−++ coup |=(* [~ +>.$])
165+ ++ coup |=(* [~ +>.$])
183Run it with these commands:
168Run it with these commands:
186−~fintud-macrep:dojo> |start %examples-pong
170+ ~fintud-macrep:dojo> |start %examples-pong
188−~fintud-macrep:dojo> :pong &examples-urbit ~sampel-sipnym
172+ ~fintud-macrep:dojo> :pong &examples-urbit ~sampel-sipnym
192−Replace `~sampel-sipnym` with another urbit. The easiest thing to
175+Replace `~sampel-sipnym` with another urbit. The easiest thing to do is
193−do is to start a moon, a sub-identity of your urbit. If you don't know how to start a moon, see [the user admin section](/docs/using/admin/). Don't
176+to start a moon, a sub-identity of your urbit. If you don't know how to
177+start a moon, see [the user admin section](/docs/using/admin/). Don't
194−forget to start the `%examples-pong` app on that urbit, too. You should
178+forget to start the `%examples-pong` app on that urbit, too. You should
195see, on the foreign urbit, this output:
179see, on the foreign urbit, this output:
198−[%receiving 'howdy']
181+ [%receiving 'howdy']
201−Most of the code should be straightforward. In `++poke-atom`,
183+Most of the code should be straightforward. In `++poke-atom`, the only
202−the only new thing is the expression `(@t arg)`, which is the type `@t` being called as a function with argument `arg`. As we already
184+new thing is the expression `(@t arg)`, which is the type `@t` being
185+called as a function with argument `arg`. As we already know, `@t` is
186+the type of "cord" text strings. In Hoon, when types are called as
187+functions, they serve as a validator function called a "clam" -- that
203−know, `@t` is the type of "cord" text strings. In Hoon, when types are called as functions, they serve as a validator function called a "clam" -- that is, a function whose domain is all nouns, and range is the given type (in this case, `@t`).
188+is, a function whose domain is all nouns, and range is the given type
189+(in this case, `@t`).
205−In simpler terms, if a clam is passed a value of its own
191+In simpler terms, if a clam is passed a value of its own type, it
206−type, it produces that value. Otherwise, it
192+produces that value. Otherwise, it produces the default value (aka the
207−produces the default value (aka the "bunt") of its type. Here we call
208−this `@t` function on the argument. This coerces the argument
193+"bunt") of its type. Here we call this `@t` function on the argument.
209−to text, so that we can print it out prettily no matter what
194+This coerces the argument to text, so that we can print it out prettily
210−we're passed.
195+no matter what we're passed.
212−The more interesting part is in `++poke-urbit`. The `urbit` mark
197+The more interesting part is in `++poke-urbit`. The `urbit` mark is an
213−is an urbit identity, and the hoon type associated with it is
198+urbit identity, and the Hoon type associated with it is `@p` (the "p"
214−`@p` (the "p" stands for "phonetic base").
199+stands for "phonetic base").
216Recall that in a `++poke` arm we produce "a list of moves and our
201Recall that in a `++poke` arm we produce "a list of moves and our
217−state". Until now, we've left the list of moves empty, since we
202+state". Until now, we've left the list of moves empty, since we haven't
218−haven't wanted to tell arvo to do anything in particular. Now we
203+wanted to tell arvo to do anything in particular. Now we want to send a
219−want to send a message to another urbit. Thus, we produce a list
204+message to another urbit. Thus, we produce a list with one element:
223−[ost %poke /sending [to-urbit-address %pong] %atom 'howdy']
206+ [ost %poke /sending [to-urbit-address %pong] %atom 'howdy']
228−The general form of a move is
210+The general form of a move is `[bone term wire *]`.
233−------------------------->app/vane-specific part of move
235Or, in pseudo-code:
212Or, in pseudo-code:
237−`["cause" sys-call/action tack-new-layer-on-cause action-specific
214+`["cause" sys-call/action tack-new-layer-on-cause action-specific information]`
240Let's walk through each of these elements step by step.
216Let's walk through each of these elements step by step.
242#### Bones ("cause")
218#### Bones ("cause")
244−If you look up `++bone` in `hoon.hoon`, you'll see that it's a
220+If you look up `++bone` in `hoon.hoon`, you'll see that it's a number
245−number (`@ud`), and that it's an opaque reference to a duct.
221+(`@ud`), and that it's an opaque reference to a duct. `++duct` in
246−`++duct` in hoon.hoon is a list of `wire`s, where `++wire` is an
222+hoon.hoon is a list of `wire`s, where `++wire` is an alias for `++path`.
247−alias for `++path`. `++path` is a list of `++span`s, which are ASCII
223+`++path` is a list of `++span`s, which are ASCII text. Thus, a duct is a
248−text. Thus, a duct is a list of paths, and a bone is an opaque
224+list of paths, and a bone is an opaque reference to it (in the same way
249−reference to it (in the same way that a Unix file
250−descriptor is an opaque reference to a file structure). Thus, to
225+that a Unix file descriptor is an opaque reference to a file structure).
251−truly understand bones, we must understand ducts.
226+Thus, to truly understand bones, we must understand ducts.
253−A duct is stack of causes, again, represented as paths, which are
228+A duct is stack of causes, again, represented as paths, which are called
254−called wires. At the bottom of every duct is a unix event, such
229+wires. At the bottom of every duct is a unix event, such as a keystroke,
255−as a keystroke, network packet, file change, or timer event.
230+network packet, file change, or timer event. When arvo is given this
256−When arvo is given this event, it routes the event to appropriate
231+event, it routes the event to appropriate kernel module for handling.
257−kernel module for handling.
232+
259−Sometimes, the module can immediately handle the event and
233+Sometimes, the module can immediately handle the event and produce any
260−produce any necessary results. For example, when we poked the
234+necessary results. For example, when we poked the `++poke-atom` arm
261−`++poke-atom` arm above, we poked %gall, our application server,
235+above, we poked %gall, our application server, which was able to respond
262−which was able to respond to our poke directly. When the module
236+to our poke directly. When the module cannot service the request itself,
263−cannot service the request itself, it sends instructions to another kernel
237+it sends instructions to another kernel module or application (the the
264−module or application (the the %gall module) to do a specified action, and produces the result from that.
238+%gall module) to do a specified action, and produces the result from
266−Furthermore, when one module sends a message to another kernel module or application, it also sends along the duct it was given
241+Furthermore, when one module sends a message to another kernel module or
242+application, it also sends along the duct it was given with its new wire
267−with its new wire tacked onto the end. Now the duct has two entries,
243+tacked onto the end. Now the duct has two entries, with the unix even on
268−with the unix even on the bottom and the kernel module that
244+the bottom and the kernel module that handled it next. This process can
269−handled it next. This process can continue indefinitely, adding
270−more and more layers onto the duct. When an entity finally
245+continue indefinitely, adding more and more layers onto the duct. When
271−produces a result, a layer is popped off the duct, and the result
246+an entity finally produces a result, a layer is popped off the duct, and
272−is passed all the way back down.
247+the result is passed all the way back down.
274−In effect, a duct is an arvo-level call stack. It's worth noting
249+In effect, a duct is an arvo-level call stack. It's worth noting that
275−that while in traditional call stacks a function call happens
250+while in traditional call stacks a function call happens synchronously
276−synchronously and returns exactly once. In arvo, multiple moves
251+and returns exactly once. In arvo, multiple moves can be sent at once,
277−can be sent at once, are evaluated asynchronously, and each
252+are evaluated asynchronously, and each one may be responded to zero or
278−one may be responded to zero or more times.
253+more times.
280The point to take home is that whatever caused `++poke-urbit` to be
255The point to take home is that whatever caused `++poke-urbit` to be
281−called is also the root cause for the network message we're
256+called is also the root cause for the network message we're trying to
282−trying to send. Thus, we say to send the network message along the given bone
257+send. Thus, we say to send the network message along the given bone
285##### Wire ('tack on new layer to duct')
260##### Wire ('tack on new layer to duct')
287−Of course, we have to push a new layer onto our duct
262+Of course, we have to push a new layer onto our duct before passing it
288−before passing it along (or responding to it directly) anywhere. This
263+along (or responding to it directly) anywhere. This layer can have any
289−layer can have any data we want in it, but we don't need anything
264+data we want in it, but we don't need anything specific here, so we just
290−specific here, so we just use the wire `/sending`
291−(`/elem1/elem2/elemN` is one syntax used to create `++path`s and
265+use the wire `/sending` (`/elem1/elem2/elemN` is one syntax used to
292−`++wire`s of N elements). If we were expecting a response (which
266+create `++path`s and `++wire`s of N elements). If we were expecting a
293−we're not), it would come back along the `/sending` wire, meaning
267+response (which we're not), it would come back along the `/sending`
294−that the path `/sending` will be passed back to the response
268+wire, meaning that the path `/sending` will be passed back to the
295−handler as an argument. Although it's not required, it's
269+response handler as an argument. Although it's not required, it's
296−generally a good idea to make the wire human-readable for
270+generally a good idea to make the wire human-readable for bug-handling
297−bug-handling purposes.
271+purposes.
299##### Term (sys-call)
273##### Term (sys-call)
301Each move also has a `term`, composed of lowercase ASCII and/or `-`.
275Each move also has a `term`, composed of lowercase ASCII and/or `-`.
302−This `term` has the sign `@tas`. In this case, out `term` is `%poke`,
276+This `term` has the sign `@tas`. In this case, out `term` is `%poke`,
303−which is the name of the particular kind of move we're sending.
277+which is the name of the particular kind of move we're sending. You can
304−You can always use `%poke` to message an app. Other common names
278+always use `%poke` to message an app. Other common names include
305−include `%warp`, to read from the filesystem; `%wait`, to
279+`%warp`, to read from the filesystem; `%wait`, to set a timer; and
306−set a timer; and `%them`, to send an http request.
280+`%them`, to send an http request.
308The move ends with `*` (that is, any noun) since each type of move takes
282The move ends with `*` (that is, any noun) since each type of move takes
309−different data. In our case, a `%poke` move takes a target
283+different data. In our case, a `%poke` move takes a target (urbit and
310−(urbit and app) and marked data, then pokes the arm of the
284+app) and marked data, then pokes the arm of the corresponding mark on
311−corresponding mark on that app on that urbit
312−with that data. `[to-urbit-address %pong]` is the target urbit and app,
285+that app on that urbit with that data. `[to-urbit-address %pong]` is the
313−`%atom` is the mark`, and `'howdy'` is the data.
286+target urbit and app, `%atom` is the mark`, and`'howdy'\` is the data.
315−When arvo receives a `%poke` move, it calls the appropriate
288+When arvo receives a `%poke` move, it calls the appropriate `++poke`.
316−`++poke`. The same mechanism is used for sending messages
289+The same mechanism is used for sending messages between apps on the same
317−between apps on the same urbit as for sending messages between
290+urbit as for sending messages between apps on different urbits.
318−apps on different urbits.
291+
320−> We said earlier that we're not expecting a response. This is
292+> We said earlier that we're not expecting a response. This is not
321−> not entirely true: the `++coup` is called when we receive
293+> entirely true: the `++coup` is called when we receive acknowledgment
322−> acknowledgment that the `++poke` was called. We don't do
294+> that the `++poke` was called. We don't do anything with this
323−> anything with this information right now, but we could.
295+> information right now, but we could.
325**Exercises**:
297**Exercises**:
327−- Extend either of the apps in the first two exercises to accept
299+- Extend either of the apps in the first two exercises to accept input
328− input over the network in the same way as `pong`.
300+ over the network in the same way as `pong`.
330−- Modify `examples-pong` to print out a message when it receives acknowledgement.
302+- Modify `examples-pong` to print out a message when it receives
331−
303+ acknowledgement.
332−- Write two apps, `even` and `odd`. When you pass an atom to
305+- Write two apps, `even` and `odd`. When you pass an atom to `even`,
333− `even`, check whether it's even. If so, divide it by two and
306+ check whether it's even. If so, divide it by two and recurse;
334− recurse; otherwise, poke `odd` with it. When `odd` recieves
307+ otherwise, poke `odd` with it. When `odd` recieves an atom, check
335− an atom, check whether it's equal to one. If so, terminate,
308+ whether it's equal to one. If so, terminate, printing "%success".
336− printing "%success". Otherwise, check whether it's odd. If
309+ Otherwise, check whether it's odd. If so, multiply it by three, add
337− so, multiply it by three, add one, and recurse; otherwise, poke
310+ one, and recurse; otherwise, poke `even` with it. When either app
338− `even` with it. When either app receives a number, print it out along with the name of the app. In the end, you should be able to watch Collatz's
311+ receives a number, print it out along with the name of the app. In
312+ the end, you should be able to watch Collatz's conjecture play out
339− conjecture play out between the two apps. Sample output:
313+ between the two apps. Sample output:
342−~fintud-macrep:dojo> :even &atom 18
317+ ~fintud-macrep:dojo> :even &atom 18
343−[%even 18]
318+ [%even 18]
344−[%odd 9]
319+ [%odd 9]
345−[%even 28]
320+ [%even 28]
346−[%even 14]
321+ [%even 14]
347−[%odd 7]
322+ [%odd 7]
348−[%even 22]
323+ [%even 22]
349−[%odd 11]
324+ [%odd 11]
350−[%even 34]
325+ [%even 34]
351−[%odd 17]
326+ [%odd 17]
352−[%even 52]
327+ [%even 52]
353−[%even 26]
328+ [%even 26]
354−[%odd 13]
329+ [%odd 13]
355−[%even 40]
330+ [%even 40]
356−[%even 20]
331+ [%even 20]
357−[%even 10]
332+ [%even 10]
358−[%odd 5]
333+ [%odd 5]
359−[%even 16]
334+ [%even 16]
360−[%even 8]
335+ [%even 8]
361−[%even 4]
336+ [%even 4]
362−[%even 2]
337+ [%even 2]
363−%success
338+ %success
366−- Put `even` and `odd` on two separate urbits and pass the
340+- Put `even` and `odd` on two separate urbits and pass the messages
367− messages over the network. Post a link to a working solution
341+ over the network. Post a link to a working solution in :talk to
368− in :talk to receive a cookie.
342+ receive a cookie.