Skip to content

Instantly share code, notes, and snippets.

@sigilante
Created June 20, 2023 15:20
Show Gist options
  • Save sigilante/57109dafa344631f55d72bf5c7fd2fcd to your computer and use it in GitHub Desktop.
Save sigilante/57109dafa344631f55d72bf5c7fd2fcd to your computer and use it in GitHub Desktop.
Hoon Prime: A Discipline for Userspace Code

Code accessibility cannot be an afterthought for Urbit development. Hoon has had a reputation for being a language of dense expressions, which we believe is now being cleared by sunshine. However, Hoon's extensive sugar syntax and irregular expressiveness can make it challenging for those relatively new to Hoon to decipher programs.

Code accessibility must be a priority for userspace Hoon. We can support developer learning and entry into the ecosystem by defining a subset of Hoon syntax that we adhere to in all of the appropriate guides and some of the userspace code.

Let's call this subset "Hoon Prime" (H´). Hoon Prime will be a code discipline within Hoon to promote a clear pathway for newer developers to understand the nature of Hoon programs before needing to grapple with the entire panoply of syntax and runes. Hoon Prime may not alway be the most concise Hoon code, and it will likely fail to maintain certain well-established preferences. (Even if there is a "better" way to write it, we should prefer this restricted discipline in H´.) Hoon Prime will allow us to onboard developers into producing generators and agents from %base-distributed models as quickly as possible.

Programming Style

Runes

The first concerns are to limit the scope of runes that must be learned to the top 27 most important ones, with another 27 context-specific runes included for particular code constructions.

  • %: cencol
  • :* coltar
  • %= cenhep (sugar preferred but not mandated)
  • |= bartis
  • ^- kethep
  • %~ censig
  • =/ tisfas (specifically preferred over =+ and =-)
  • ?: wutcol
  • ?~ wutsig
  • %- cenhep
  • |- barhep
  • :~ colsig
  • :- colhep
  • ?- wuthep
  • .+ dotlus (only as sugar syntax +())
  • => tisgar
  • |% barcen
  • |. bardot
  • !! zapzap
  • ;: miccol
  • ?+ wutlus
  • |^ barket
  • ~& sigpam (with logging levels)
  • |_ barcab
  • $% buccen
  • $? bucwut
  • $: buccol

The following are allowed in specific contexts or forms:

  • ^= kettis (only as sugar syntax p=q)
  • =< tisgal (illustrative in a few particular cases)
  • =. tisdot (illustrative for "edit a variable")
  • .= dottis (only as sugar syntax =())
  • ;~ micsig (only for parsers)
  • ^: ketcol (only to explain structure v. value mode; prefer sugar syntax ,)
  • ^* kettar (only as sugar syntax *)
  • ?> wutgar (only for type resolution)
  • ?& wutpam (only as sugar syntax &())
  • %+ cenlus (as contrastive with %- and %:)
  • =^ tisket
  • |* bartar
  • =* tistar (only standard agent boilerplate)
  • ~| sigbar
  • ?! wutzap (only as sugar syntax !)
  • ?| wutbar (only as sugar syntax |())
  • !> zapgar (mainly for illustration)
  • !, zapcom (mainly for illustration)
  • != zaptis (mainly for illustration)
  • $_ buccab (only as sugar syntax _)
  • ;; micmic
  • ?^ wutket
  • ?@ wutpat
  • !< zapgal
  • ;/ micfas and other Sail runes (except in Sail materials)
  • .^ dotket
  • ;< micgal

The following should be specifically avoided in Hoon Prime:

  • =+ tislus
  • ?= wuttis
  • ^+ ketlus
  • ?. wutdot
  • ~ sig runes generally, aside from ~& sigpam
  • ?< wutgal
  • =| tisbar
  • :_ colcab (mentioned in resources but not used in H´ code)
  • =? tiswut
  • :+ collus
  • =- tishep
  • :^ colket
  • %^ cenket
  • =, tiscom
  • %_ cencab
  • ^? ketwut
  • ^. ketdot
  • |~ barsig
  • %. cendot
  • |$ barbuc
  • |@ barpat (unless needed for |* wet gates)
  • ?< watgal
  • .* dottar (except in Nock materials)
  • =; tismic
  • =: tiscol
  • ^| ketbar
  • %* centar
  • |: buccol (prefer $_ buccab in irregular form)
  • !? zapwut
  • =~ tissig
  • .? dotwut (except in Nock materials)
  • ^~ ketsig
  • ?# wuthax (decision may be revised vis-à-vis ?= wuttis)
  • |? barwut
  • !@ zappat
  • ^& ketpam

To reiterate, these are not claims about Hoon generally—Hoon Prime is a pedagogical code discipline, not the future of Hoon.

Sugar Syntax

Sugar syntax should be deployed thoughtfully.

The following syntax expressions are explicitly blessed:

  • .+ dotlus (only as sugar syntax +())
  • ^= kettis (only as sugar syntax p=q)
  • .= dottis (only as sugar syntax =())
  • ^: ketcol (only to explain structure v. value mode; prefer sugar syntax ,)
  • ^* kettar (only as sugar syntax *)
  • ?& wutpam (only as sugar syntax &())
  • ?! wutzap (only as sugar syntax !)
  • ?| wutbar (only as sugar syntax |())
  • $_ buccab (only as sugar syntax _)
  • $? bucwut (as both ?() and explicitly)

The following constructions are explicitly barred:

  • Do not use tag+value; prefer [%tag value].
    • See the note on each below.
  • Do not use `this for an empty set of cards; prefer [~ this]. (The structure is the same but the intent of a unit is different.)

Specific rules will accustom developers to use patterns before running into deeper concepts like the Hoon type system. These may be controversial but each has a specific pedagogical motivation.

  • Prefer head-tagged unions of values when multiple kinds of values should be included, e.g. in a $? bucwut type union.
  • Type unions can only be made over constants. (No ?(@t tape) sorts of expressions.)
  • Explicitly mark lists as such, rather than relying on null-terminated tuples.
  • All : col runes can be used when explaining rune alternatives.

Literate Programming

Hoon Prime should also adopt a standard of literate programming. Several example files already display such a self-documenting nature:

Our userspace code accessibility model should allow contributors from widely different skill levels to interact. We need to surface and document code patterns as cleanly as possible in the code we distribute.

We need to upgrade as much code as possible to A standards per the style guide.

Agents

Agent files should hew to the following standards:

  • /lib/agent-name.hoon
    • There should only be one /lib file per agent.
    • If JSON handling is necessary, store it in a file /lib/agent-name/json.hoon with ++dejs and ++enjs arms.
  • /mar/agent-name/action.hoon
    • There should be one /mar file per agent action.
    • Agent actions should be named from action, update, result, effect.
    • Defer all JSON handling to the appropriate mark, never in the main /app file.
  • /sur/agent-name.hoon
    • There should be only one /sur file per agent.

Prefer these constructions:

  • =* this .
  • Use the agentio library when possible.
  • Use Rudder and Schooner when possible.
  • Use (pole knot) over path in agent arms. (Just don't teach path in beginner materials in that context.)
  • After it has been introduced pedagogically, prefer the nested core pattern about 50% of the time. Show both versions (conventional and nested core) when feasible. Treat the nested core pattern as a release version refactor rather than a starting point for many learner cases.

Rules

  • Do not weigh heavier expressions down to the bottom with rune inversion (like :_ or =-). (Some of the Hoon Style Guide is strategically deprecated for Hoon Prime code.)
  • Do not privilege three-letter and four-letter names in userspace. There could still be a naming pattern (like five-letter words) that increases the code aesthetics (gap alignment in blocks &c.).
  • Be careful with metaphors. A good metaphor can illuminate, while a bad one will obfuscate. Still, have fun.
  • In working with type unions, use each to distinguish values. All values should be head-tagged semantically, and this need not match the aura form (as with +scot); that is, prefer %text instead of %t for a string.
  • Userspace apps put out by the Urbit Foundation or submitted in completion of a bounty should include tests and docs (see below).

Unit Testing and Docs

We need to include comments and unit tests so people can see how and why code works like it does.

  • /tests/agent-name/tests.hoon with multiple test files permitted if desired.

Documentation should be compatible with %docs.

  • /doc/agent-name should include the appropriate Udon (Markdown) files.

References

This document has benefited from a decade of Hoon code and organic best practices.

@sigilante
Copy link
Author

Hmm, that's an interesting direction too: we have experimented with more tree-based thinking in Hoon School and at minimum a section in subject-oriented programming on =+ tislus with subject retrievel would be a compelling treatment.

@hoclun-rigsep
Copy link

Yes—along these lines, if you really want to withhold some of the sacred runes from total novices, withhold the | runes, |% excepted. Until the novice groks that a core is a [battery payload], a gate a [one-arm-battery sample context] etc, he gets no sugar. Call it Hoon Double Prime.

@bonbud-macryg
Copy link

I'd have appreciated having had core-nature drilled into my brain earlier. Though thinking back to Hooniversity it was nice to start with "use |= to define inputs and use ^- to define outputs" as a total scrub who wanted to get writing his own little functions quickly.

@eamsden
Copy link

eamsden commented Oct 6, 2023

=?, ?=, :_ and a few others are not runes you want to ban if you want readable, maintainable code.

=?  a.thing  conditional  new-value
rest

in the alternate

=.  a.thing  ?:  conditional  new-value  a.thing
rest

trivially violates DRY

?# is not even merged yet is it?

@eamsden
Copy link

eamsden commented Oct 6, 2023

(This proposal came up in a discussion thus my comments on it now)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment