first draft of quickstart and partial network messages

This commit is contained in:
Philip C Monk 2015-11-17 18:38:47 -05:00
parent d55da0ff39
commit 5927312f10
2 changed files with 360 additions and 0 deletions

View File

@ -0,0 +1,172 @@
---
next: true
sort: 1
title: Quickstart
---
# Quickstart
If you're interested in programming in urbit, you've come to the
right place. This is a jump-in, get-your-hands-dirty,
roll-in-the-mud-and-figure-things-out intro to programming hoon
on urbit.
The first thing to do, of course, is get an urbit up and running.
The only ingredients are a Unix box and a pinch of courage, so
check out the [installation
instructions](http://urbit.org/docs/user/install) to get started.
Once urbit is installed, if you have an invitation, it's a planet
like `~fintud-macrep` and a ticket like
`~fortyv-tombyt-tabsen-sonres`. Run
bin/urbit -w fintud-macrep -t fortyv-tombyt-tabsen-sonres
(You can leave the `~` on, but it annoys some Unix shells.)
If you don't have an invitation, pick a nickname for your comet,
like `mycomet`. Urbit will randomly generate a 128-bit plot:
bin/urbit -c mycomet
Either way, creating your urbit will take some time. Some of
this time involves creating keys; some of it involves downloading
code over Urbit itself.
If you turn off your pier at any time (either "nicely" with `^D`
from talk or the dojo or by power-failure, oom-killer, or other
calamity), then you can start it up again with the path to your
pier directory (your planet name if you have an invitation,
otherwise the name you chose after `-c`):
bin/urbit fintud-macrep
or
bin/urbit mycomet
## Basic operation
Out of the box, your urbit is running two default appliances,
`:dojo` (a shell or REPL) and `:talk`. Switch between them with
`^X`. Note that all apps share an output log, but `^X` switches
the prompt.
`^D` from either default appliance exits the urbit process.
If your plot is `~fintud-macrep`, the dojo prompt is
~fintud-macrep:dojo>
Type any Hoon expression at the command line and see the result:
~fintud-macrep:dojo> (add 2 2)
You'll see:
> (add 2 2)
4
~fintud-macrep:dojo>
You can also run commands from the dojo. Unix users should
recognize some of these (`%` means current working directory).
> +ls %
ape/
arvo/
docs/
elem/hook
front/
gen/
index/hook
lib/
mar/
pub/
spec/nock/%/txt
sur/
tree/
tree-gen/tree-include/hook
try/readme/md
> +cat %/try/readme
/~nibrun-dozlyr-wictuc-folrex/home/~2015.11.17..21.22.58..ee8e/try/readme/md
/=try=/
This is the try desk. Feel free to try out whatever you want here.
Often it's useful to edit urbit files from Unix. Use `|mount` to
set up a Dropbox-style sync directory in your pier directory:
> |mount %
>=
> |unmount %
>=
Look inside your pier directory to find your files, and edit them
with your favorite Unix text editor.
Sometimes you want to get files from another urbit. There's two
main commands to do this.
> |merge %my-examples ~wactex-ribmex %examples
>=
; ~wactex-ribmex is your neighbor
; ~wactex-ribmex is your neighbor
[time passes...]
merged with strategy %init
This pulls a bunch of examples from `~wactex-ribmex`'s `%examples`
desk and puts them in our `%my-examples` desk. A desk is a
branch (in the git branch sense) of our filesystem.
You can, of course, merge the examples into your `%home`
(default) desk if you wish. Merging into a new desk creates it,
while merging into an existing desk does an intelligent git-style
merge, with conflict resolution and stuff.
> |sync %my-examples ~wactex-ribmex %examples
>=
activated sync from %examples on ~wactex-ribmex to %my-examples
sync succeeded from %examples on ~wactex-ribmex to %my-examples
> |unsync %my-examples ~wactex-ribmex %examples
ended autosync from %examples on ~wactex-ribmex to %my-examples
`|sync` does an initial `|merge`, then listens for changes on the
foreign desk and runs `|merge` automatically whenever it changes.
By default your `%home` desk is synced to your parent's `%kids`
desk, so the entire network is upgraded at once. You may, of
course, unsync it, but this voids your warranty.
You can change which desk is your current working directory with:
> =% /=my-examples
When you change your desk all commands will be using the files
from that desk. Unfortunately, changing your working directory
to anywhere but the top directory is currently
[broken](http://github.com/urbit/urbit/issues/565). If this
is fixed when you're reading this, please submit a pull request
for this document explaining how to do it!
The last command we'll discuss in this quickstart is `+moon`,
which only works on planets.
> +moon
"moon: ~ramnec-rossug-fintud-macrep; ticket: ~holtyl-mognyl-dostyp-moslud"
This generates a random moon and ticket. A moon is a subidentity
of your planet, so it's a separate urbit that's associated with
your planet. If your planet is off, then your moon won't
function very well over the network (it'll work just fine
locally, of coures).
You can start up your moon with `bin/urbit -w moon-name -t
ticket`. We recommend doing this for development because there
are still some instabilities that have the potential to explode
your planet if you develop on it. If this happens, then your
planet will be unusable until the next continuity breach. If you
tell us how you exploded your planet, we may give you a
replacement, but it's still a hassle for you.
Don't worry too much about exploding your moons -- you have four
billion of them, and they get replenished after every continuity
breach. Still do file a bug, though.

View File

@ -0,0 +1,188 @@
---
hide: true
next: false
sort: 3
title: Network Messages
---
Enough of pure hoonery. Let's get to the good stuff. Let's get
our planets to talk to each other.
Of course, for talking to be of any use, we need someone
listening. What we've written up until now are just shell
commands that produce a value and then disappear. We need an
actual app to listen for messages from another planet. Let's
take a look at a very basic one.
```
:: There is no love that is not an echo
::
:::: /hoon/echo/ape
::
/? 314
|%
++ move ,*
--
!:
|_ [bowl state=~]
++ poke-noun
|= arg=*
^- [(list move) _+>.$]
~& [%argument arg]
[~ +>.$]
--
```
This is a very simple app that does only one thing. If you poke
it with a value it prints that out. You have to start the app,
then you can poke it from the command line.
```
> |start %echo
>=
> :echo 5
[%argument 5]
> :echo [1 2]
[%argument [1 2]]
```
Most of the app code should be simple enough to guess its
function. The important part of this code is the definition of
`++poke-noun`.
Once an app starts, it's always on in the background, and you
interact with it by sending it messages. The most
straightforward way to do that is to poke it from the command
line. When you do that, `++poke-noun` is called from your app.
In our case, `++poke-noun` takes an argument `arg` and prints it
out with `~&`. This is an unusual rune that formally "does
nothing", but the interpreter detects it and printfs the first
child. This is a slightly hacky way of printing to the console,
and we'll get to the correct way later on.
But what does `++poke-noun` produce? The phrase to remember is
"a list of moves and our state". Urbit is a message passing
system, so whenver we want to do something that interacts with
the rest of the system we send a message. Thus, the first thing
that `++poke-noun` produces is a list of messages, called
"moves". In this case, we don't actually want the system to do
anything, so we produce the empty list, `~`.
The second thing `++poke-noun` produces is our state. `+>.$`
refers to a particular address in our subject where our formal
app state is stored. It'll become clear why this is later on,
but for now pretend that `+>.$` is a magic invocation that means
"app state".
---
But what is our app state, exactly? In Unix systems, application
state is just a block of memory, which you need to serialize to
disk if you want to keep it around for very long.
In urbit, app state is a single (usually complex) value. In our
example, we don't have any special state, so we defined
`state=~`, meaning that our state is null. Of course, `state` is
just a name we're assigning to it, and you're free to use
whatever name you want.
Since urbit is purely functional, we can't just implicitly "have"
and "change" our state. Rather, it's explicitly passed to us, in
the `|_ [bowl state=~]` line, and we produce the new state with
`+>.$` in the `[~ +>.$]` line.
Two points you may be wondering about. Firstly, `bowl` is a set
of general global state that is managed by the system. It
includes things like `now` (current time), `our` (our urbit
identity), and `eny` (256 bits of guaranteed-fresh entropy). For
the full list of things in `++bowl`, search for `++ bowl` (note
the double space) in `/arvo/zuse.hoon`.
> This is a very common technique in learning hoon. While some
> documentation exists, often the easiest way to learn about an
> identifier you see in code is to search in `/arvo/zuse.hoon`
> and `/arvo/hoon.hoon` for it. These are our two "standard
> libraries", and they're usually not hard to read. Since
> urbit's codebase is relatively small (those two files are less
> than 15000 lines of code combined, and besides the standard
> library they include the hoon parser and compiler, plus the
> /arvo microkernel), you can usually use the code and the
> comments as reference doc.
Second point is that urbit needs no "serialize to disk" step.
Everything you produce in the app state is persistent across
calls to the app, restarts of the urbit, and even power failure.
If you want to write to the filesystem, you can, but it's not
needed for persistence. Urbit has transactional events, which
makes it an ACID operating system. Persistence is just another
one of those things you don't have to worry about when
programming in urbit.
As fascinating as state is, we don't actually need any state to
accomplish our immediate goal, which is to get apps on two urbits
talking to each other. We'll discuss state more in a later
chapter.
---
Anyway, that's a lot of theory, let's get back to coding. Let's
say we want to only accept a number, and then print out the
square of that number.
```
/? 314
|%
++ move ,*
--
!:
|_ [bowl state=~]
::
++ poke-atom
|= arg=@
^- [(list move) _+>.$]
~& [%square (mul arg arg)]
[~ +>.$]
--
```
A few things have changed. Firstly, we no longer accept
arbitrary nouns because we can only square atoms. Thus, our
argument is now `arg=@`. Secondly, it's `++poke-atom` rather
than `++poke-noun`.
Are there other `++poke`s? Definitely. In fact, `noun` and
`atom` are just two of arbitrarily many "marks". A mark is
fundamentally a type definition, and each mark is defined in the
`/mar` directory. Some marks have conversion routines to other
marks, and some have diff, path, and merge algorithms. None of
these are required for a mark to exist, though.
`noun` and `atom` are two of dozens of predefined marks, and the
user may add more at will. The type associated with `noun` is
`*`, and the type associated with `atom` is `@`.
Data constructed on the command line is by default marked with
`noun`. In this case, the app is expecting an atom, so we have
to explicitly mark the data with `atom`.
```
> |start %square
> :square 6
gall: %square: no poke arm for noun
> :square &atom 6
[%square 36]
```
Marks are powerful, and they're the backbone of urbit's data
pipeline, so we'll be getting quite used to them.
Let's write our first network message!
-don't forget to explain new hoon concepts ([])
-excercises
-then walk through more in depth
-move app state section to somewhere later
-put in interactive code snippets and explain a lil (bowl)