4title: Subject-oriented programming
7# Urbyte 2: Subject-oriented programming
9Thanks for reading Urbytes 0 and 1! In Urbyte 2, we'll take
10nouns for granted and have some real fun with them.
12Let's restart our engines:
17ames: on localhost, UDP 31337.
18http: live (insecure, public) on 8080
19http: live ("secure", public) on 8443
20http: live (insecure, loopback) on 12321
28We're playing in the Urbit `:dojo`. The dojo is sort of like a
29cross between a Lisp REPL and the Unix shell. (If you know the
30Unix shell, the Urbit command line has the same history model and
31Emacs editing commands.)
33The dojo has its own command language, which is a superset of
34Hoon. Any Hoon expression is a command. But not all commands
37(The dojo is not the only command-line app on your Urbit. By
38default there is one other, `:talk`. Since you're on a fakezod,
39you can only talk to yourself. If you accidentally press `ctrl-x`,
40it will put you into `:talk`; press `ctrl-x` again to switch back.)
44Like the Unix shell, the dojo has command variables. Type
50You've set the dojo variable `a` to the value `42`. The dojo
51puts this binding in the Hoon subject for expressions to use.
66To unbind `a`, just omit the value:
72You removed `a` from the subject. (We can bind it again later, or
73bind over it without removing it.)
80Now trying to use `a` is an error.
82## Subject-oriented programming
84What is this *subject* thing, anyway? We put `a` in what?
86Most programming languages have something called a *scope* or an
87*environment* or a *context*. This is a data structure that
88contains the variables and functions an expression can use.
90In a normal language, the environment is not a first-class value.
91You cannot save an environment in a variable, compute an
92expression against the environment in the variable, etc, etc.
94In Hoon or any "subject-oriented" language, an expression is
95executed against one normal value, the *subject*. In Hoon, of
96course, the subject is a noun.
100Up to now, we've only built constants. By definition, a constant
101doesn't use the subject.
103It would be nice to start with the subject every dojo expression
104gets. But that subject is pretty complex. Instead, let's make a
105simple noun from the kinds of atoms we've already learned about:
108> =a [42 [%foo .6.28 ~m45] 0xdead.beef]
111 {@ud {$foo @rs @dr} @ux}
112[42 [%foo .3.14 ~m45] 0xdead.beef]
118The syntax `expression:expression` uses the product of the second
119expression as the subject of the first. So we're using `a` as
120the subject of the expression `420`.
122Of course, `420` is a constant expression. It doesn't care what
130We can't use `a` as the subject of even a simple addition. How
131could we? There's no `add` function in our `a`. It sometimes
132takes new Hoon programmers a little while before they realize
133that there really isn't a scope or environment in Hoon.
137So what can we do with this subject? How can we get data out of
138it? Let's keep working with our little test subject `a`.
140The most basic way to access the subject is *tree geometry*.
141Every noun is a binary tree; every noun in the tree has a number
142which is its address. The root of the tree is `1`. If the
143address of a cell is `n`, the address of its head is `2n` and the
144address of its tail is `2n+1`.
159The syntax for a fragment of the subject at a tree address, or
160*axis*, is just `+axis`. So:
164[[%foo .3.14 ~m45] 0xdead.beef]
175The fragment retains the type it had when we built it.
177Another (equivalent) way to think of tree addressing involves
178binary. As before, the root of the tree is at address `1`. For
179the node of a tree at some address `b`, where `b` is binary,
180you get the address of the head by concatenating a `0` to
181the end of `b`; and to get the tail, concatenate a `1` at the
182end. For example, the head of the node at binary address `111`
183is at `1110`, and the tail is at `1111`.
187We can obviously get anything we want out of the subject by tree
188geometry. But that's not really how we'd like to program. We'd
189much rather *label* subtrees with convenient, memorable symbols.
191For example, suppose our tree looked like:
205Then instead of writing `+2`, we could write `x`, and so on.
207Let's replace our test subject `a` with a new noun built around
208this tree of *labeled surfaces*.
211> =a [x=42 y=[p=%foo q=.6.28 r=~m45] z=0xdead.beef]
219[p=%foo q=.6.28 r=~m45]
226Surfaces might remind you of attributes in an object. But again,
227attributes in an object are a symbol table. There is no symbol
228table here -- just a tree search.
230An expression like the label `x` or the axis `+2`, which
231designates a fragment or feature of the subject, is called a
232*limb*. A list of limbs connected with `.` is a *wing*.
234To remind you that you're not in Kansas anymore, the syntax for a
235wing, like `q.y` above, means means "q inside y." In a classic
236object-oriented system, of course, this would be written `y.q`,
237that is, attribute `q` within object `y`. In Hoon, `q.y` means
238"find limb `y`, then find limb `q` inside that."
240## Surfaces versus fragments
242Once again, Hoon has no symbol tables. When we put a surface
243on a noun, the surface label is part of that noun's type. It's
244not part of the cell or other structure that contains the noun.
245This will take a little getting used to:
261When we take fragment 2 of the labeled subject, the *surface
262comes with it*. `+2` is not `42` but rather `x=42`. We can
263take the surface off with `x.+2`.
265## The search algorithm
267In resolving a label to a fragment axis, we search the subject
268type in a depth-first traverse.
270If we find a surface that matches the limb, we succeed. If we
271find a surface that doesn't match the limb, we fail. If we find
272a cell, we search first head, then tail.
276What if the same label appears twice in one noun? Let's modify
277our subject slightly as a test case:
287 {x/@ud y/{p/$foo q/@rs r/@dr} x/@ux}
288[x=42 y=[p=%foo q=.6.28 r=~m45] x=0xdead.beef]
299We don't want to hide any part of the noun from an expression.
300So the modified limb `^x` *skips* the first match with a surface
301`x`, getting us to our `0xdead.beef`. This is a unary notation:
302`^^x` would skip the first two matches.
306Above, we mutated our first noun with the flashy `a(+7 x=z:a)`.
308Of course we are not really "modifying" a noun. Hoon is a pure
309language. We are making an edited copy. `a(+7 x=z:a)` means "a
310copy of `a`, with limb `+7` replaced by the product of `x=z:a`."
312We can edit multiple (disjoint) wings in one expression:
315> ? a(+7 [%hello %world], q.y .3.14)
316 {x/@ud y/{p/$foo q/@rs r/@dr} $hello $world}
317[x=42 y=[p=%foo q=.3.14 r=~m45] %hello %world]
320Notice that nothing stopped us from changing `+7` from
321`x=0xdead.beef` to `[%hello %world]`. Since the mutated
322copy is a different noun, it has a different type.
324(And remember that since `[x y z]` means `[x [y z]]`,
325`[x y [%hello %world]]` means `[x y %hello %world]`.)
329It should be reasonably clear how Hoon's system of fragments and
330surfaces parallels variables, records or structures in a
331classical language. But where is Hoon's equivalent of objects:
332values which bind code to data?
334The Hoon equivalent of an object is a *core*. As usual in Hoon,
335the resemblance is inexact. A core has a set of computed
336attributes, or *arms*. Each arm is an expression whose subject
337is the core. There is no argument, so an arm is not a method.
339Physically, a core is always a cell `[battery payload]`, where
340the *payload* is any noun, and the *battery* is a tree of
341formulas in Nock (Hoon's functional assembly language) that
342implements the arms. (A battery is like a C++ vtable, sort of.)
344## The search algorithm
346As you'd expect with a computed attribute, there is only one
347namespace and one search algorithm. We just extend the algorithm
348described above. And an expression which uses a label can't know
349whether the subject will resolve it to a surface fragment (a
352If we're searching a core and the label matches one of the core's
353arms, we compute the arm against the core. If the label is not
354found, we search into the payload of the core.
358When you type these examples, make sure you get the number of
359spaces exactly right. Hoon syntax is not whitespace-sensitive
360in general, except that "one space" is always a different token
361from "two or more spaces."
372> =b :per a :core ++ foo x ++ bar [q.y foo] --
375We're seeing some Hoon regular forms for the first time. `x:a`
376turns out to be an irregular relative of the regular `:per` form.
378We'll get more into syntax in a later Urbyte. If some of these
379examples seem syntactically a little funky, this isn't usually
380way we'd do them in "real life." We don't normally write cores
381on a single command line. In a file this would be:
391which is much more readable, at least once you get used to it.
392Let's look at the core itself:
396<2.spy {x/@ud y/{p/$foo q/@rs r/@dr} x/@ux}>
400[[0 6] [0 58] 9 4 0 1]
403 {x/@ud y/{p/$foo q/@rs r/@dr} x/@ux}
404[x=42 y=[p=%foo q=.6.28 r=~m45] x=0xdead.beef]
407When we print `b`, or any core, we see that typed noun printing
408can't be an invertible function in Hoon.
410We actually can read the battery (with `+2:b` above), but it's
411just Nock code, not typed data. `<2.spy>` tells us the battery
412has two arms and hashes to the three-letter code `spy`.
414When printing a full core, we don't even print the payload data,
415just its type. But our `+3:b` confirms the `[battery payload]`
416structure of the core. Remember, `+2` is the head and `+3` is
419Finally, let's use this thing:
439Now that we've made a test subject which is a core, we can look
440directly at the real dojo subject:
444[ [ [ a=[x=42 y=[p=%foo q=.6.28 r=~m45] x=0xdead.beef]
445 b=<2.spy {x/@ud y/{p/$foo q/@rs r/@dr} x/@ux}>
447 now=~2016.7.18..08.05.15..0b5c
448 eny=0vl.hsfrh.tg642.g5o21.1n80b.0h141.0vuan.pm8o4.77ovg.96rk0.n26nn
449 our=~palnul-wolmev-bonfex-danred--tilwen-midlux-bolfus-nocser
452 <283.xzp 42.ajz 407.xtr 110.xht 1.ztu $151>
456We see a bunch of surfaces: our custom `a` and `b`; standard
457surfaces for identity, date, and entropy; and a ginormous core
458stack with *over eight hundred* total arms.
460To be exact, the syntax `<283.xzp 42.ajz 407.xtr 110.xht 1.ztu
461$151>` denotes a stack of six cores, each of whose payload is
462another core, until the innermost payload `%151` (the Hoon
463version number). This stack is our standard library, from which
464comes `add` and other fine functions. (We don't know how to
465write a Hoon function yet, but we're getting way closer.)
467Let's clean up our subject, just to be hygienic:
474 now=~2016.7.18..08.10.42..36a0
475 eny=0vf.8j71j.hlqim.k340u.q0ual.v2cd8.cfa65.vkbte.e733g.ehihg.e8aog
476[ [ our=~palnul-wolmev-bonfex-danred--tilwen-midlux-bolfus-nocser
479 <283.xzp 42.ajz 407.xtr 110.xht 1.ztu $151>
483Again, remember that `=a` is not Hoon syntax, but `:dojo` syntax.
484How the dojo assembles this subject remains a mystery. But it's
485not a particularly interesting mystery.
489And we're done! Type `|exit` to exit:
492~palnul_nocser:dojo> |exit
497## Questions and/or exercises
499As always, these questions are optional and only for fun.
501What's the best way to construct a core which acts as a function?
502What do you do to call the function?
504Why don't any other languages use subject-oriented programming?
505Which languages are most similar to it?
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list